sequencetools

This module implements tools for defining and handling different kinds of the sequences (time-series) of hydrological models.

Module sequencetools implements the following members:


class hydpy.core.sequencetools.FastAccessIOSequence[source]

Bases: hydpy.core.variabletools.FastAccess

Provides fast access to the values of the sequences of a sequence subgroup and supports the handling of internal data series during simulations.

The following details are of relevance for HydPy developers only.

FastAccessIOSequence is applied in Python mode only. In Cython mode it is replaced by model-specific Cython extension classes, which are computationally more efficient. For compatibility with these extension classes, FastAccessIOSequence objects work with dynamically set instance members. Suppose there is a sequence named seq1 which is 2-dimensional, then its associated attributes are:

  • seq1 (ndarray): The actual sequence values.

  • _seq1_ndim (int): Number of dimensions.

  • _seq1_length_0 (int): Length in the first dimension.

  • _seq1_length_1 (int): Length in the second dimension.

  • _seq1_ramflag (bool): Handle internal data in RAM?

  • _seq1_diskflag (bool): Handle internal data on disk?

  • _seq1_path (str): Path of the internal data file.

  • _seq1_file (open()): Object handling the internal data file.

Note that the respective SubSequences and Sequence_ objects initialise, change, and apply these dynamical attributes. To handle them directly is error-prone and thus not recommended.

open_files(idx: int)None[source]

Open all files with an activated disk flag and seek the position indicated by the given index.

close_files()None[source]

Close the internal data files of all handled sequences with an activated diskflag.

load_data(idx: int)None[source]

Load the internal data of all sequences with an activated memoryflag.

Read from a file if the corresponding disk flag is activated; read from working memory if the corresponding ram flag is activated.

save_data(idx: int)None[source]

Save the internal data of all sequences with an activated flag.

Write to a file if the corresponding disk flag is activated; write to working memory if the corresponding ram flag is activated.

class hydpy.core.sequencetools.FastAccessInputSequence[source]

Bases: hydpy.core.sequencetools.FastAccessIOSequence

FastAccessIOSequence subclass specialised for input sequences.

set_pointerinput(name: str, pdouble: hydpy.cythons.autogen.pointerutils.PDouble)None[source]

Use the given PDouble object as the pointer for the 0-dimensional InputSequence object with the given name.

class hydpy.core.sequencetools.FastAccessOutputSequence[source]

Bases: hydpy.core.sequencetools.FastAccessIOSequence

FastAccessIOSequence subclass specialised for output sequences.

set_pointeroutput(name: str, pdouble: hydpy.cythons.autogen.pointerutils.PDouble)None[source]

Use the given PDouble object as the pointer for the 0-dimensional OutputSequence object with the given name.

update_outputs()[source]

Pass the internal data of all sequences with activated output flag.

class hydpy.core.sequencetools.FastAccessLinkSequence[source]

Bases: hydpy.core.variabletools.FastAccess

FastAccessIOSequence subclass specialised for link sequences.

alloc(name: str, length: int)None[source]

Allocate enough memory for the given vector length for the LinkSequence with the given name.

Cython extension classes need to define alloc() if there is at least one 1-dimensional LinkSequence subclasses.

dealloc(name: str)None[source]

Free the previously allocated memory of the LinkSequence with the given name.

Cython extension classes need to define alloc() if there is at least one 1-dimensional LinkSequence subclasses.

set_pointer0d(name: str, value: hydpy.cythons.autogen.pointerutils.Double)[source]

Use the given PDouble object as the pointer of the 0-dimensional LinkSequence object with the given name.

Cython extension classes need to define set_pointer0d() if there is at least one 0-dimensional LinkSequence subclasses.

set_pointer1d(name: str, value: hydpy.cythons.autogen.pointerutils.Double, idx: int)[source]

Use the given PDouble object as one of the pointers of the 1-dimensional LinkSequence object with the given name.

The given index defines the vector position of the pointer.

Cython extension classes need to define set_pointer0d() if there is at least one 1-dimensional LinkSequence subclasses.

get_value(name: str)Union[float, numpy.ndarray][source]

Return the actual value(s) the LinkSequence object with the given name is pointing to.

set_value(name: str, value: Union[float, Iterable[float]])None[source]

Change the actual value(s) the LinkSequence object with the given name is pointing to.

class hydpy.core.sequencetools.FastAccessNodeSequence[source]

Bases: hydpy.core.sequencetools.FastAccessIOSequence

FastAccessIOSequence subclass specialised for Node objects.

In contrast to other FastAccessIOSequence subclasses, FastAccessNodeSequence only needs to handle a fixed number of sequences, Sim and Obs. It thus can define the related attributes explicitly.

sim: hydpy.cythons.autogen.pointerutils.Double
obs: hydpy.cythons.autogen.pointerutils.Double
load_simdata(idx: int)None[source]

Load the next sim sequence value (of the given index).

save_simdata(idx: int)None[source]

Save the last sim sequence value (of the given index).

load_obsdata(idx: int)None[source]

Load the next obs sequence value (of the given index).

load_data(idx: int)None[source]

Call both method load_simdata() and method load_obsdata().

save_data(idx: int)None[source]

Alias for method save_simdata().

reset(idx: int = 0)None[source]

Reset the actual value of the simulation sequence to zero.

fill_obsdata(idx: int = 0)None[source]

Use the current sim value for the current obs value if obs is nan.

class hydpy.core.sequencetools.InfoArray(array, info=None)[source]

Bases: numpy.ndarray

numpy ndarray subclass that stores and tries to keep an additional info attribute.

>>> from hydpy.core.sequencetools import InfoArray
>>> array = InfoArray([1.0, 2.0], info="this array is short")
>>> array
InfoArray([ 1.,  2.])
>>> array.info
'this array is short'
>>> subarray = array[:1]
>>> subarray
InfoArray([ 1.])
>>> subarray.info
'this array is short'
class hydpy.core.sequencetools.Sequences(model: modeltools.Model, cls_inlets: Optional[Type[InletSequences]] = None, cls_receivers: Optional[Type[ReceiverSequences]] = None, cls_inputs: Optional[Type[InputSequences]] = None, cls_fluxes: Optional[Type[FluxSequences]] = None, cls_states: Optional[Type[StateSequences]] = None, cls_logs: Optional[Type[LogSequences]] = None, cls_aides: Optional[Type[AideSequences]] = None, cls_outlets: Optional[Type[OutletSequences]] = None, cls_senders: Optional[Type[SenderSequences]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None, cythonmodule: Optional[module] = None)[source]

Bases: object

Base class for handling all sequences of a specific model.

Sequences objects handle nine sequence subgroups as attributes such as the inlets and the receivers subsequences:

>>> from hydpy.examples import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> sequences = hp.elements.land_dill.model.sequences
>>> bool(sequences.inlets)
False
>>> bool(sequences.fluxes)
True

Iteration makes only the non-empty subgroups available which are handling Sequence_ objects:

>>> for subseqs in sequences:
...     print(subseqs.name)
inputs
fluxes
states
logs
outlets
>>> len(sequences)
5

Class Sequences provides some methods related to reading and writing time-series data, which (directly or indirectly) call the corresponding methods of the handled IOSequence objects. In most cases, users should prefer to use the related methods of class HydPy but using the ones of class Sequences can be more convenient when analysing a specific model in-depth.

To introduce these methods, we first change two IO-related settings:

>>> from hydpy import round_
>>> pub.options.checkseries = False
>>> pub.sequencemanager.generaloverwrite = True

Method activate_ram() and method deactivate_ram() enables/disables handling time-series in rapid access memory and method save_series() writes time-series to files:

>>> sequences.activate_ram()
>>> sequences.inputs.t.ramflag
True
>>> sequences.inputs.t.series = 1.0, 2.0, 3.0, 4.0
>>> with TestIO():
...     sequences.save_series()
>>> sequences.deactivate_ram()
>>> sequences.inputs.t.ramflag
False
>>> sequences.inputs.t.series
Traceback (most recent call last):
...
AttributeError: Sequence `t` of element `land_dill` is not requested to make any internal data available.

Method activate_disk() and deactivate_disk() enables/disables handling time-series on disk and method load_series() reads time-series from files:

>>> with TestIO():
...     sequences.activate_disk()
>>> sequences.inputs.t.diskflag
True
>>> with TestIO():
...     sequences.load_series()
...     round_(sequences.inputs.t.series)
1.0, 2.0, 3.0, 4.0
>>> with TestIO():
...     sequences.deactivate_disk()
>>> sequences.inputs.t.diskflag
False
>>> hasattr(sequences.inputs.t, "series")
False

Methods ram2disk() and disk2ram() allow moving data from RAM to disk and from disk to RAM, respectively:

>>> sequences.activate_ram()
>>> sequences.inputs.t.ramflag
True
>>> sequences.inputs.t.series = 1.0, 2.0, 3.0, 4.0
>>> with TestIO():
...     sequences.ram2disk()
>>> sequences.inputs.t.diskflag
True
>>> with TestIO():
...     round_(sequences.inputs.t.series)
1.0, 2.0, 3.0, 4.0
>>> with TestIO():
...     sequences.disk2ram()
>>> round_(sequences.inputs.t.series)
1.0, 2.0, 3.0, 4.0

The documentation on class IOSequence explains the underlying functionalities of class IOSequence in more detail.

>>> pub.options.checkseries = True
>>> pub.sequencemanager.generaloverwrite = False
model: modeltools.Model
inlets: InletSequences
receivers: ReceiverSequences
inputs: InputSequences
fluxes: FluxSequences
states: StateSequences
logs: LogSequences
aides: AideSequences
outlets: OutletSequences
senders: SenderSequences
property iosubsequences

Yield all relevant IOSequences objects handled by the current Sequences object.

The currently available IO-subgroups are inputs, fluxes, and states.

>>> from hydpy import prepare_model
>>> model = prepare_model("hland_v1", "1d")
>>> for subseqs in model.sequences.iosubsequences:
...     print(subseqs.name)
inputs
fluxes
states

However, not all models implement sequences for all these subgroups. Property iosubsequences only yields those subgroups which are non-empty:

>>> model = prepare_model("hstream_v1", "1d")
>>> for subseqs in model.sequences.iosubsequences:
...     print(subseqs.name)
states
activate_disk()None[source]

Call method activate_disk() of all handled IOSequences objects.

deactivate_disk()None[source]

Call method deactivate_disk() of all handled IOSequences objects.

activate_ram()None[source]

Call method activate_ram() of all handled IOSequences objects.

deactivate_ram()None[source]

Call method deactivate_ram() of all handled IOSequences objects.

ram2disk()[source]

Call method ram2disk() of all handled IOSequences objects.

disk2ram()[source]

Call method disk2ram() of all handled IOSequences objects.

load_series()[source]

Call method load_series() of all handled IOSequences objects.

save_series()[source]

Call method save_ext() of all handled IOSequences objects.

open_files(idx: int = 0)None[source]

Call method open_files() of all handled IOSequences objects.

close_files()None[source]

Call method close_files() of all handled IOSequences objects.

load_data(idx: int)None[source]

Call method load_data() of the handled InputSequences object.

save_data(idx: int)None[source]

Call method save_data() of the handled FluxSequences and StateSequences objects.

reset()None[source]

Call method reset() of all handled ConditionSequence objects.

property conditionsequences

Generator object yielding all conditions (StateSequence and LogSequence objects).

property conditions

A nested dictionary which contains the values of all condition sequences.

See the documentation on property conditions for further information.

load_conditions(filename: Optional[str] = None)None[source]

Read the initial conditions from a file and assign them to the respective StateSequence and LogSequence objects handled by the actual Sequences object.

The documentation on method load_conditions() of class HydPy explains how to read and write condition values for complete HydPy projects in the most convenient manner. However, using the underlying methods load_conditions() and save_conditions() directly offers the advantage to specify alternative filenames. We demonstrate this through using the land_dill Element object of the LahnH example project and focussing on the values of state sequence SM:

>>> from hydpy.examples import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> sequences = hp.elements.land_dill.model.sequences
>>> 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)

From now on, we work in the freshly created condition directory test:

>>> with TestIO():
...     pub.conditionmanager.currentdir = "test"

We set all soil moisture values to zero and write the updated values to the file cold_start.py:

>>> sequences.states.sm(0.0)
>>> with TestIO():   
...     sequences.save_conditions("cold_start.py")

Trying to reload from the written file (after changing the soil moisture values again) without passing the file name fails due to assuming the elements name as file name base:

>>> sequences.states.sm(100.0)
>>> with TestIO():   
...     sequences.load_conditions()
Traceback (most recent call last):
...
FileNotFoundError: While trying to load the initial conditions of element `land_dill`, the following error occurred: [Errno 2] No such file or directory: '...land_dill.py'

One does not need to state the file extensions (.py) explicitly:

>>> with TestIO():
...     sequences.load_conditions("cold_start")
>>> sequences.states.sm
sm(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)

Note that determining the file name automatically requires a proper reference to the related Element object:

>>> del sequences.model.element
>>> with TestIO():
...     sequences.save_conditions()
Traceback (most recent call last):
...
RuntimeError: While trying to save the actual conditions of element `?`, the following error occurred: To load or save the conditions of a model from or to a file, its filename must be known.  This can be done, by passing filename to method `load_conditions` or `save_conditions` directly.  But in complete HydPy applications, it is usally assumed to be consistent with the name of the element handling the model.  Actually, neither a filename is given nor does the model know its master element.
save_conditions(filename: Optional[str] = None)None[source]

Query the actual conditions of the StateSequence and LogSequence objects handled by the actual Sequences object and write them into an initial condition file.

See the documentation on method load_conditions() for further information.

trim_conditions()None[source]

Call method trim() of each handled ConditionSequence.

trim_conditions() is just a convenience function for calling method trim() of all StateSequence and LogSequence objects returned by property conditionsequences. We demonstrate its functionality by preparing an instance of application model lland_v1, using its available default values, and defining out-of-bound values of the soil moisture state sequence BoWa:

>>> from hydpy import prepare_model, pub
>>> pub.timegrids = "2000-01-01", "2000-01-10", "1d"
>>> with pub.options.usedefaultvalues(True):
...     model = prepare_model("lland_v1", "1d")
...     model.parameters.control.nhru(2)
>>> model.sequences.states.bowa = -100.0
>>> model.sequences.trim_conditions()
>>> model.sequences.states.bowa
bowa(0.0, 0.0)
class hydpy.core.sequencetools.SubSequences(master: GroupType, cls_fastaccess: Optional[Type[FastAccessType]] = None)[source]

Bases: hydpy.core.variabletools.SubVariables[hydpy.core.sequencetools.SequencesType, hydpy.core.sequencetools.SequenceType, hydpy.core.variabletools.FastAccessType]

Base class for handling subgroups of sequences.

Each SubSequences object has a fastaccess attribute. When working in pure Python mode, this is an instance either of (a subclass of) class FastAccess:

>>> from hydpy import classname, Node, prepare_model, pub
>>> with pub.options.usecython(False):
...     model = prepare_model("lland_v1")
>>> classname(model.sequences.logs.fastaccess)
'FastAccess'
>>> classname(model.sequences.inputs.fastaccess)
'FastAccessInputSequence'
>>> from hydpy.core.sequencetools import FastAccessNodeSequence
>>> with pub.options.usecython(False):
...     node = Node("test1")
>>> isinstance(node.sequences.fastaccess, FastAccessNodeSequence)
True

When working in Cython mode (which is the default mode and much faster), fastaccess is an object of Cython extension class FastAccessNodeSequence of module sequenceutils or of a Cython extension class specialised for the respective model and sequence group:

>>> with pub.options.usecython(True):
...     model = prepare_model("lland_v1")
>>> classname(model.sequences.inputs.fastaccess)
'InputSequences'
>>> from hydpy.cythons.sequenceutils import FastAccessNodeSequence
>>> with pub.options.usecython(True):
...     node = Node("test2")
>>> isinstance(Node("test2").sequences.fastaccess, FastAccessNodeSequence)
True

See the documentation of similar class SubParameters for further information. However, note the difference that model developers should not subclass SubSequences directly but specialised subclasses like FluxSequences or StateSequences instead.

property name

The class name in lower case letters omitting the last eight characters (“equences”).

>>> from hydpy.core.sequencetools import StateSequences
>>> class StateSequences(StateSequences):
...     CLASSES = ()
>>> StateSequences(None).name
'states'
vars: GroupType
class hydpy.core.sequencetools.ModelSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.SubSequences[hydpy.core.sequencetools.Sequences, hydpy.core.sequencetools.ModelSequenceType, hydpy.core.variabletools.FastAccessType]

Base class for handling model-related subgroups of sequences.

class hydpy.core.sequencetools.IOSequences(master: GroupType, cls_fastaccess: Optional[Type[FastAccessType]] = None)[source]

Bases: hydpy.core.sequencetools.SubSequences[hydpy.core.sequencetools.SequencesType, hydpy.core.sequencetools.IOSequenceType, hydpy.core.sequencetools.FastAccessIOSequenceType]

Subclass of SubSequences, specialised for handling IOSequence objects.

activate_ram()[source]

Call method activate_ram() of all handled IOSequence objects.

deactivate_ram()[source]

Call method deactivate_ram() of all handled IOSequence objects.

activate_disk()[source]

Call method activate_disk() of all handled IOSequence objects.

deactivate_disk()[source]

Call method deactivate_disk() of all handled IOSequence objects.

ram2disk()[source]

Call method ram2disk() of all handled IOSequence objects.

disk2ram()[source]

Call method disk2ram() of all handled IOSequence objects.

load_series()[source]

Call method load_ext() of all handled IOSequence objects.

save_series()[source]

Call method save_ext() of all handled IOSequence objects.

open_files(idx: int = 0)None[source]

Call method open_files() of the FastAccessIOSequence object handled as attribute fastaccess.

close_files()[source]

Call method close_files() of the FastAccessIOSequence object handled as attribute fastaccess.

vars: GroupType
class hydpy.core.sequencetools.ModelIOSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.IOSequences[hydpy.core.sequencetools.Sequences, hydpy.core.sequencetools.ModelIOSequenceType, hydpy.core.sequencetools.FastAccessIOSequenceType], hydpy.core.sequencetools.ModelSequences[hydpy.core.sequencetools.ModelIOSequenceType, hydpy.core.sequencetools.FastAccessIOSequenceType]

Base class for handling model-related subgroups of IOSequence objects.

load_data(idx: int)None[source]

Call method load_data() of the FastAccessIOSequence object handled as attribute fastaccess.

save_data(idx: int)None[source]

Call method save_data() of the FastAccessIOSequence object handled as attribute fastaccess.

vars: GroupType
class hydpy.core.sequencetools.InputSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.ModelIOSequences[InputSequence, hydpy.core.sequencetools.FastAccessInputSequence]

Base class for handling InputSequence objects.

vars: GroupType
class hydpy.core.sequencetools.OutputSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.ModelIOSequences[hydpy.core.sequencetools.OutputSequenceType, hydpy.core.sequencetools.FastAccessOutputSequence]

Base class for handling OutputSequence objects.

update_outputs()None[source]

Call method update_outputs() of the FastAccessOutputSequence object handled as attribute fastaccess.

vars: GroupType
class hydpy.core.sequencetools.FluxSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.OutputSequences[FluxSequence]

Base class for handling FluxSequence objects.

property name

Always return the string “fluxes”.

property numericsequences

Iterator for numerical flux sequences.

numerical means that the NUMERIC class attribute of the actual sequence is True:

>>> from hydpy import prepare_model
>>> model = prepare_model("dam_v001")
>>> len(model.sequences.fluxes)
11
>>> for seq in model.sequences.fluxes.numericsequences:
...     print(seq)
inflow(nan)
actualrelease(nan)
flooddischarge(nan)
outflow(nan)
vars: GroupType
class hydpy.core.sequencetools.StateSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.OutputSequences[StateSequence]

Base class for handling StateSequence objects.

new2old()None[source]

Call method new2old() of all handled StateSequence objects.

reset()None[source]

Call method reset() of all handled StateSequence objects.

class hydpy.core.sequencetools.LogSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.ModelSequences[LogSequence, hydpy.core.variabletools.FastAccess]

Base class for handling LogSequence objects.

reset()None[source]

Call method reset() of all handled LogSequence objects.

class hydpy.core.sequencetools.AideSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.ModelSequences[AideSequence, hydpy.core.variabletools.FastAccess]

Base class for handling AideSequence objects.

class hydpy.core.sequencetools.LinkSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.ModelSequences[hydpy.core.sequencetools.LinkSequenceType, hydpy.core.sequencetools.FastAccessLinkSequence]

Base class for handling LinkSequence objects.

class hydpy.core.sequencetools.InletSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.LinkSequences[InletSequence]

Base class for handling “inlet” LinkSequence objects.

class hydpy.core.sequencetools.OutletSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.LinkSequences[OutletSequence]

Base class for handling “outlet” LinkSequence objects.

class hydpy.core.sequencetools.ReceiverSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.LinkSequences[ReceiverSequence]

Base class for handling “receiver” LinkSequence objects.

class hydpy.core.sequencetools.SenderSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.LinkSequences[SenderSequence]

Base class for handling “sender” LinkSequence objects.

class hydpy.core.sequencetools.Sequence_(subvars: SubVariablesType)[source]

Bases: hydpy.core.variabletools.Variable[hydpy.core.sequencetools.SubSequencesType, hydpy.core.variabletools.FastAccessType]

Base class for defining different kinds of sequences.

Note that model developers should not derive their model-specific sequence classes from Sequence_ directly but from the “final” subclasses provided in module sequencetools (e.g. FluxSequence).

From the model developer perspective and especially from the user perspective, Sequence_ is only a small extension of its base class Variable. One relevant extension is that (only the) 0-dimensional sequence objects come with a predefined shape:

>>> from hydpy import prepare_model
>>> model = prepare_model("lland_v1", "1d")
>>> model.sequences.fluxes.qa.shape
()
>>> evpo = model.sequences.fluxes.evpo
>>> evpo.shape
Traceback (most recent call last):
...
hydpy.core.exceptiontools.AttributeNotReady: Shape information for variable `evpo` can only be retrieved after it has been defined.

For high numbers of entries, the string representation puts the names of the constants within a list (to make the string representations executable under Python 3.6; this behaviour changes as soon as Python 3.7 becomes the oldest supported version):

>>> evpo.shape = (255,)
>>> evpo    
evpo(nan, nan, ..., nan, nan)
>>> evpo.shape = (256,)
>>> evpo    
evpo([nan, nan, ..., nan, nan])

For consistency with the usage of Parameter subclasses, Sequence_ objects are also “callable” for setting their values (but in a much less and flexible manner):

>>> evpo(2.0)
>>> evpo    
evpo([2.0, 2.0, ..., 2.0, 2.0])

Under the hood, class Sequence_ also prepares some attributes of its FastAccess object, used for performing the actual simulation calculations. Framework developers should note that the respective fastaccess attributes contain both the name of the sequence and the name of the original attribute in lower case letters. We take NDIM as an example:

>>> evpo.fastaccess._evpo_ndim
1

Some of these attributes require updating under some situations. For example, other sequences than AideSequence objects require a “length” attribute, which needs to be updated each time the sequence’s shape changes:

>>> evpo.fastaccess._evpo_length
256
TYPE
INIT: float = 0.0
NUMERIC: bool
strict_valuehandling: ClassVar[bool] = False
property subseqs

Alias for attribute subvars.

property initinfo

A tuple containing the initial value and True or a missing value and False, depending on the actual Sequence_ subclass and the actual value of option usedefaultvalues.

In the following, we do not explain property initinfo itself but show how it affects initialising new Sequence_ objects. Therefore, let us define a sequence test class and prepare a function for initialising it and connecting the resulting instance to a ModelSequences object:

>>> from hydpy.core.sequencetools import Sequence_, ModelSequences
>>> from hydpy.core.variabletools import FastAccess
>>> class Test(Sequence_):
...     NDIM = 0
...     _CLS_FASTACCESS_PYTHON = FastAccess
>>> class SubGroup(ModelSequences):
...     CLASSES = (Test,)
...     _CLS_FASTACCESS_PYTHON = FastAccess
>>> def prepare():
...     subseqs = SubGroup(None)
...     test = Test(subseqs)
...     test.__hydpy__connect_variable2subgroup__()
...     return test

By default, making use of the INIT attribute is disabled:

>>> prepare()
test(nan)

Enable it through setting usedefaultvalues to True:

>>> from hydpy import pub
>>> with pub.options.usedefaultvalues(True):
...     prepare()
test(0.0)

Attribute INIT of class Sequence_ comes with the value 0.0 by default, which should be reasonable for most Sequence_ subclasses. However, subclasses can define other values. Most importantly, note the possibility to set INIT to None for sequences that do not allow defining a reasonabe initial value for all possible situations:

>>> Test.INIT = None
>>> prepare()
test(nan)
>>> with pub.options.usedefaultvalues(True):
...     prepare()
test(nan)
name: str = 'sequence_'
unit: str = '?'
class hydpy.core.sequencetools.IOSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.Sequence_[hydpy.core.sequencetools.IOSequencesType, hydpy.core.sequencetools.FastAccessIOSequenceType]

Base class for sequences with input/output functionalities.

The IOSequence subclasses InputSequence, FluxSequence, StateSequence, and NodeSequence all implement similar special properties, which configure the processes of reading and writing time-series files. In the following, property filetype_ext is taken as an example to explain how to handle them:

Usually, each sequence queries its current “external” file type from the SequenceManager object stored in module pub:

>>> from hydpy import pub
>>> from hydpy.core.filetools import SequenceManager
>>> pub.sequencemanager = SequenceManager()

Depending if the actual sequence stems from InputSequence, FluxSequence, StateSequence, or NodeSequence, either inputfiletype, fluxfiletype, statefiletype, or nodefiletype are queried:

>>> pub.sequencemanager.inputfiletype = "npy"
>>> pub.sequencemanager.fluxfiletype = "asc"
>>> pub.sequencemanager.nodefiletype = "nc"
>>> from hydpy.core import sequencetools as st
>>> st.InputSequence(None).filetype_ext
'npy'
>>> st.FluxSequence(None).filetype_ext
'asc'
>>> st.NodeSequence(None).filetype_ext
'nc'

Alternatively, you can specify filetype_ext for each sequence object individually:

>>> seq = st.InputSequence(None)
>>> seq.filetype_ext
'npy'
>>> seq.filetype_ext = "nc"
>>> seq.filetype_ext
'nc'
>>> del seq.filetype_ext
>>> seq.filetype_ext
'npy'

If neither a specific definition nor a SequenceManager object is available, property filetype_ext raises the following error:

>>> del pub.sequencemanager
>>> seq.filetype_ext
Traceback (most recent call last):
...
RuntimeError: For sequence `inputsequence` attribute filetype_ext cannot be determined.  Either set it manually or prepare `pub.sequencemanager` correctly.

How to read and write time-series files is explained in the documentation on modules filetools and netcdftools in some detail. However, reading and writing time-series files is disabled by default, due to reasons of efficiency. You first need to prepare the series attribute of the relevant IOSequence objects. Typically, you do this by calling methods like prepare_inputseries() of class HydPy. Here, we use the related features the IOSequence class itself, which is a little more complicated but also more flexible when scripting complex workflows.

We use the LahnH example project and focus on the input and flux sequences:

>>> from hydpy.examples import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> inputs = hp.elements.land_lahn_1.model.sequences.inputs
>>> fluxes = hp.elements.land_lahn_1.model.sequences.fluxes

IOSequence objects come with the properties ramflag and diskflag, telling if the respective time-series is available in RAM, on disk, or not available at all. Input sequences are the only ones who need to have one flag activated. Otherwise, the input series would not be available during simulation runs. For example, input sequence T stores its time-series data in RAM internally, which is the much faster approach and should be preferred, as long as limited storage is not an issue:

>>> inputs.t.ramflag
True
>>> inputs.t.diskflag
False
>>> from hydpy import repr_, round_
>>> round_(inputs.t.series, 1)
-0.7, -1.5, -4.2, -7.4

Convenience function prepare_full_example_2() also activates the ramflag of all flux sequences, which is not necessary to perform a successful simulation but is required to query the complete time-series of simulated values afterwards (otherwise, only the last simulated value would available after a simulation run):

>>> fluxes.tc.ramflag
True
>>> round_(fluxes.tc.series[:, 0])
nan, nan, nan, nan

Use activate_ram() or activate_disk() to force a sequence to handle time-series data in RAM or on disk, respectively. We now activate the diskflag of flux sequence TMean (which automatically disables the ramflag). Note that we need to change the current working directory to the iotesting directory temporarily (by using class TestIO) to make sure to create that the related file in the right directory:

>>> with TestIO():
...     fluxes.tmean.activate_disk()
...     repr_(fluxes.tmean.filepath_int)    
'...iotesting/LahnH/series/temp/land_lahn_1_flux_tmean.bin'

The user can access the time-series data in the same manner as if being handled in RAM:

>>> fluxes.tmean.ramflag
False
>>> fluxes.tmean.diskflag
True
>>> with TestIO():
...     round_(fluxes.tmean.series)
nan, nan, nan, nan

For completeness of testing, we also activate the diskflag of a 1-dimensional sequence:

>>> from pprint import pprint
>>> with TestIO():
...     fluxes.fracrain.activate_disk()
...     pprint(sorted(os.listdir("LahnH/series/temp")))
['land_lahn_1_flux_fracrain.bin', 'land_lahn_1_flux_tmean.bin']

Apply methods deactivate_ram() or deactivate_disk() for sequences that do not provide data relevant for your analysis:

>>> fluxes.ep.deactivate_ram()
>>> fluxes.ep.ramflag
False
>>> fluxes.ep.diskflag
False
>>> fluxes.ep.series
Traceback (most recent call last):
...
AttributeError: Sequence `ep` of element `land_lahn_1` is not requested to make any internal data available.

After a simulation run, the series of flux sequence EP is still not available but the time-series data of the other discussed series with either true ramflag or diskflag values are:

>>> with TestIO():
...     hp.simulate()
>>> fluxes.ep.series = 1.0
Traceback (most recent call last):
...
AttributeError: Sequence `ep` of element `land_lahn_1` is not requested to make any internal data available.
>>> round_(fluxes.q1.series, 1)
0.4, 0.4, 0.4, 0.4
>>> round_(fluxes.tc.series[:, 0], 1)
0.2, -0.6, -3.4, -6.6
>>> with TestIO():
...     round_(fluxes.tmean.series, 1)
-1.0, -1.8, -4.5, -7.7
>>> with TestIO():
...     round_(fluxes.fracrain.series[:, 0], 1)
0.3, 0.0, 0.0, 0.0

You cannot only access the time-series data of individual IOSequence objects, but you can also modify it. See, for example, the simulated time series for flux sequence PC (adjusted precipitation), which is zero, because the values of input sequence P (given precipitation) are also zero:

>>> round_(fluxes.pc.series[:, 0], 1)
0.0, 0.0, 0.0, 0.0

We can assign different values to attribute series of sequence P, perform a new simulation run, and see that the newly calculated time-series of sequence PC reflects our data modification:

>>> inputs.p.ramflag
True
>>> inputs.p.series = 10.0
>>> with TestIO():
...     hp.simulate()
>>> round_(fluxes.pc.series[:, 0], 1)
10.2, 11.3, 11.3, 11.3

Next, we show that the same feature works for time-series data handled on disk. Therefore, we first call method ram2disk(), which disables ramflag and enables diskflag without any loss of information:

>>> with TestIO():
...     inputs.p.ram2disk()
...     pprint(sorted(os.listdir("LahnH/series/temp")))
['land_lahn_1_flux_fracrain.bin',
 'land_lahn_1_flux_tmean.bin',
 'land_lahn_1_input_p.bin']
>>> inputs.p.ramflag
False
>>> inputs.p.diskflag
True
>>> with TestIO():
...     round_(inputs.p.series, 1)
10.0, 10.0, 10.0, 10.0

Data modifications still influence simulation runs as to be expected:

>>> with TestIO():
...     inputs.p.series = 20.0
...     hp.simulate()
...     round_(fluxes.pc.series[:, 0], 1)
20.5, 22.6, 22.6, 22.6

Method disk2ram() is the counterpart to ram2disk():

>>> with TestIO():
...     inputs.p.disk2ram()
...     pprint(sorted(os.listdir("LahnH/series/temp")))
['land_lahn_1_flux_fracrain.bin', 'land_lahn_1_flux_tmean.bin']
>>> inputs.p.ramflag
True
>>> inputs.p.diskflag
False
>>> round_(inputs.p.series, 1)
20.0, 20.0, 20.0, 20.0

Method deactivate_disk() works analogue to deactivate_ram():

>>> with TestIO():
...     fluxes.fracrain.deactivate_disk()
...     pprint(sorted(os.listdir("LahnH/series/temp")))
['land_lahn_1_flux_tmean.bin']
>>> fluxes.fracrain.ramflag
False
>>> fluxes.fracrain.diskflag
False

Both methods deactivate_ram() and deactivate_disk() do nothing in case the respective flag is False already:

>>> fluxes.pc.deactivate_ram()
>>> with TestIO():
...     fluxes.fracrain.deactivate_disk()

You can query property memoryflag, if you are only interested to know if a sequence handles stores its time-series data, but not how:

>>> fluxes.pc.memoryflag
False
>>> fluxes.tmean.memoryflag
True
>>> inputs.p.memoryflag
True

Another convenience property is seriesshape, which combines the length of the simulation period with the shape of the individual IOSequence object:

>>> inputs.p.seriesshape
(4,)
>>> fluxes.pc.seriesshape
(4, 13)

Note that resetting the shape of am IOSequence object does not change how it handles its internal time-series data, but results in a loss of current information:

>>> fluxes.tc.seriesshape
(4, 13)
>>> fluxes.fastaccess._tc_length
13
>>> round_(fluxes.tc.series[:, 0], 1)
0.2, -0.6, -3.4, -6.6
>>> fluxes.tc.shape = (2,)
>>> fluxes.tc.seriesshape
(4, 2)
>>> fluxes.fastaccess._tc_length
2
>>> round_(fluxes.tc.series[:, 0], 1)
nan, nan, nan, nan

Resetting the shape of IOSequence objects which are not storing their internal time-series data works too:

>>> fluxes.pc.seriesshape
(4, 13)
>>> fluxes.fastaccess._pc_length
13
>>> round_(fluxes.pc.series[:, 0], 1)
Traceback (most recent call last):
...
AttributeError: Sequence `pc` of element `land_lahn_1` is not requested to make any internal data available.
>>> fluxes.pc.shape = (2,)
>>> fluxes.pc.seriesshape
(4, 2)
>>> fluxes.fastaccess._pc_length
2
>>> round_(fluxes.pc.series[:, 0], 1)
Traceback (most recent call last):
...
AttributeError: Sequence `pc` of element `land_lahn_1` is not requested to make any internal data available.
filetype_ext: ClassVar[hydpy.core.sequencetools._FileType]
dirpath_ext: ClassVar[hydpy.core.sequencetools._DirPathProperty]
aggregation_ext: ClassVar[hydpy.core.sequencetools._AggregationProperty]
overwrite_ext: ClassVar[hydpy.core.sequencetools._OverwriteProperty]
rawfilename

DefaultProperty handling the filename without ending for external and internal data files.

>>> from hydpy.core.sequencetools import StateSequence
>>> class Test(StateSequence):
...     descr_device = "node1"
...     descr_sequence = "subgroup_test"
>>> Test(None).rawfilename
'node1_subgroup_test'
filename_ext

The full filename of the external data file.

The “external” filename consists of rawfilename and of filetype_ext. For simplicity, we add the attribute rawfilename to the initialised sequence object in the following example:

>>> from hydpy.core.sequencetools import StateSequence
>>> seq = StateSequence(None)
>>> seq.rawfilename = "test"
>>> seq.filetype_ext = "nc"
>>> seq.filename_ext
'test.nc'
property filename_int

The full filename of the internal data file.

The “internal” filename consists of rawfilename and the file ending .bin. For simplicity, we add the attribute rawfilename to the initialised sequence object in the following example:

>>> from hydpy.core.sequencetools import StateSequence
>>> seq = StateSequence(None)
>>> seq.rawfilename = "test"
>>> seq.filename_int
'test.bin'
dirpath_int

The absolute path of the directory of the internal data file.

Usually, each sequence queries its current “internal” directory path from the SequenceManager object stored in module pub:

>>> from hydpy import pub, repr_, TestIO
>>> from hydpy.core.filetools import SequenceManager
>>> pub.sequencemanager = SequenceManager()

We overwrite basepath and prepare a folder in the iotesting directory to simplify the following examples:

>>> basepath = SequenceManager.basepath
>>> SequenceManager.basepath = "test"
>>> TestIO.clear()
>>> import os
>>> with TestIO():
...     os.makedirs("test/temp")

Generally, property dirpath_int queries property tempdirpath:

>>> from hydpy.core import sequencetools as st
>>> seq = st.InputSequence(None)
>>> with TestIO():
...     repr_(seq.dirpath_int)
'test/temp'

Alternatively, you can specify dirpath_int for each sequence object individually:

>>> seq.dirpath_int = "path"
>>> os.path.split(seq.dirpath_int)
('', 'path')
>>> del seq.dirpath_int
>>> with TestIO():
...     os.path.split(seq.dirpath_int)
('test', 'temp')

If neither a specific definition nor a SequenceManager object is, property dirpath_int raises the following error:

>>> del pub.sequencemanager
>>> seq.dirpath_int
Traceback (most recent call last):
...
RuntimeError: For sequence `inputsequence` the directory of the internal data file cannot be determined.  Either set it manually or prepare `pub.sequencemanager` correctly.

Remove the basepath mock:

>>> SequenceManager.basepath = basepath
filepath_ext

The absolute path to the external data file.

The path pointing to the “external” file consists of dirpath_ext and filename_ext. For simplicity, we define both manually in the following example:

>>> from hydpy.core.sequencetools import StateSequence
>>> seq = StateSequence(None)
>>> seq.dirpath_ext = "path"
>>> seq.filename_ext = "file.npy"
>>> from hydpy import repr_
>>> repr_(seq.filepath_ext)
'path/file.npy'
filepath_int

The absolute path to the internal data file.

The path pointing to the “internal” file consists of dirpath_int and filename_int, which itself is defined by rawfilename. For simplicity, we define both manually in the following example:

>>> from hydpy.core.sequencetools import StateSequence
>>> seq = StateSequence(None)
>>> seq.dirpath_int = "path"
>>> seq.rawfilename = "file"
>>> from hydpy import repr_
>>> repr_(seq.filepath_int)
'path/file.bin'
update_fastaccess()None[source]

Update the FastAccessIOSequence object handled by the actual IOSequence object.

Users do not need to apply the method update_fastaccess() directly. The following information should be relevant for framework developers only.

The main documentation on class Sequence_ mentions that the FastAccessIOSequence attribute handles some information about its sequences, but this information needs to be kept up-to-date by the sequences themselves. This updating is the task of method update_fastaccess(), which some other methods of class IOSequence call. We show this via the hidden attribute length, which is 0 after initialisation, and automatically set to another value when assigning it to property shape of IOSequence subclasses as NKor:

>>> from hydpy import prepare_model
>>> model = prepare_model("lland_v1")
>>> nkor = model.sequences.fluxes.nkor
>>> nkor.fastaccess._nkor_length
0
>>> nkor.shape = (3,)
>>> nkor.fastaccess._nkor_length
3
activate_ram()None[source]

Demand reading/writing internal data from/to RAM.

See the main documentation on class IOSequence for further information.

activate_disk()None[source]

Demand reading/writing internal data from/to hard disk.

See the main documentation on class IOSequence for further information.

deactivate_ram()None[source]

Prevent from reading/writing internal data from/to hard disk.

See the main documentation on class IOSequence for further information.

deactivate_disk()None[source]

Prevent from reading/writing internal data from/to hard disk.

See the main documentation on class IOSequence for further information.

ram2disk()None[source]

Move internal data from RAM to disk.

See the main documentation on class IOSequence for further information.

disk2ram()None[source]

Move internal data from disk to RAM.

See the main documentation on class IOSequence for further information.

property ramflag

A flag telling if the actual IOSequence object makes its internal time-series data available using RAM space.

See the main documentation on class IOSequence for further information.

property diskflag

A flag telling if the actual IOSequence object makes its internal time-series data available using disk space.

See the main documentation on class IOSequence for further information.

property memoryflag

A flag telling if the actual IOSequence object makes its internal time-series data available somehow.

See the main documentation on class IOSequence for further information.

property shape

A tuple containing the actual lengths of all dimensions.

When setting a new shape of an IOSequence object, one automatically calls method update_fastaccess() and, if necessary, prepares the new internal series array.

See the main documentation on class IOSequence for further information.

property seriesshape

The shape of the whole time-series (time being the first dimension).

property numericshape

The shape of the array of temporary values required for the relevant numerical solver.

The class ELSModel, being the base of the “dam” model, uses the “Explicit Lobatto Sequence” for solving differential equations and therefore requires up to eleven array fields for storing temporary values. Hence, the numericshape of the 0-dimensional sequence Inflow is eleven:

>>> from hydpy import prepare_model
>>> model = prepare_model("dam")
>>> model.sequences.fluxes.inflow.numericshape
(11,)

Changing the shape through a little trick (just for demonstration purposes) shows that there are eleven entries for each “normal” Inflow value:

>>> from hydpy.models.dam.dam_fluxes import Inflow
>>> shape = Inflow.shape
>>> Inflow.shape = (2,)
>>> model.sequences.fluxes.inflow.numericshape
(11, 2)
>>> Inflow.shape = shape

Erroneous configurations result in the following error:

>>> del model.numconsts
>>> model.sequences.fluxes.inflow.numericshape
Traceback (most recent call last):
...
AttributeError: The `numericshape` of a sequence like `inflow` depends on the configuration of the actual integration algorithm.  While trying to query the required configuration data `nmb_stages` of the model associated with element `?`, the following error occurred: 'Model' object has no attribute 'numconsts'
property series

Internal time-series data within an InfoArray covering the whole initialisation period (defined by the sim Timegrid of the global Timegrids object available in module pub).

property simseries

Read and write access to the data of property series for the actual simulation period (defined by the sim Timegrid of the global Timegrids object available in module pub).

>>> from hydpy.examples import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> t = hp.elements.land_lahn_1.model.sequences.inputs.t
>>> pub.timegrids.sim.dates = "1996-01-02", "1996-01-04"
>>> from hydpy import print_values
>>> print_values(t.series)
-0.705395, -1.505553, -4.221268, -7.446349
>>> print_values(t.simseries)
-1.505553, -4.221268
>>> t.simseries = 1.0, 2.0
>>> print_values(t.series)
-0.705395, 1.0, 2.0, -7.446349
property evalseries

Read and write access to the data of property series for the actual evaluation period (defined by the eval_ Timegrid of the global Timegrids object available in module pub).

>>> from hydpy.examples import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> t = hp.elements.land_lahn_1.model.sequences.inputs.t
>>> pub.timegrids.eval_.dates = "1996-01-02", "1996-01-04"
>>> from hydpy import print_values
>>> print_values(t.series)
-0.705395, -1.505553, -4.221268, -7.446349
>>> print_values(t.evalseries)
-1.505553, -4.221268
>>> t.evalseries = 1.0, 2.0
>>> print_values(t.series)
-0.705395, 1.0, 2.0, -7.446349
load_ext()None[source]

Read the internal data from an external data file.

Method load_ext() only calls method load_file() of class SequenceManager passing itself as the only argument. Hence, see the documentation on the class SequenceManager for further information. The following example only shows the error messages when load_file() is missing due to incomplete project configurations:

>>> from hydpy.core.sequencetools import StateSequence
>>> StateSequence(None).load_ext()
Traceback (most recent call last):
...
hydpy.core.exceptiontools.AttributeNotReady: While trying to load the external time-series data of `statesequence`, the following error occurred: Attribute sequencemanager of module `pub` is not defined at the moment.
adjust_series(timegrid_data: timetools.Timegrid, values: numpy.ndarray)numpy.ndarray[source]

Adjust a time-series to the current initialisation period.

Note that, in most HydPy applications, method adjust_series() is called by other methods related to reading data from files and does not need to be called by the user directly. If you want to call it directly for some reasons, you need to make sure that the shape of the given numpy ndarray fits the given Timegrid object.

Often, time-series data available in (external) data files cover a longer period than required for an actual simulation run. Method adjust_series() selects the relevant data by comparing the initialisation Timegrid available in module pub and the given “data” Timegrid object. We explain this behaviour by using the LahnH example project and focussing on the Obs sequence of Node dill:

>>> from hydpy.examples import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> obs = hp.nodes.dill.sequences.obs

With identical initialisation and data time grids, method adjust_series() returns the given data completely:

>>> from hydpy import Timegrid
>>> import numpy
>>> with TestIO(), pub.options.checkseries(False):
...     obs.adjust_series(Timegrid("1996-01-01", "1996-01-05", "1d"),
...                       numpy.arange(4, dtype=float))
array([ 0.,  1.,  2.,  3.])

For “too long” available data, it only returns the relevant one:

>>> with TestIO(), pub.options.checkseries(False):
...     obs.adjust_series(Timegrid("1995-12-31", "1996-01-07", "1d"),
...                       numpy.arange(7, dtype=float))
array([ 1.,  2.,  3.,  4.])

For “too short” available data, the behaviour differs depending on option checkseries. With checkseries being enabled, method adjust_series() raises a RuntimeError. With checkseries being disabled, it extends the given array with nan values (using method adjust_short_series()):

>>> with TestIO(), pub.options.checkseries(True):
...     obs.adjust_series(Timegrid("1996-01-02", "1996-01-04", "1d"),
...                       numpy.zeros((3,)))   
Traceback (most recent call last):
...
RuntimeError: For sequence `obs` of node `dill` the initialisation time grid (Timegrid("1996-01-01 00:00:00", "1996-01-05 00:00:00", "1d")) does not define a subset of the time grid of the external data file `...dill_obs_q.asc` (Timegrid("1996-01-02 00:00:00", "1996-01-04 00:00:00", "1d")).
>>> with TestIO(), pub.options.checkseries(False):
...     obs.adjust_series(Timegrid("1996-01-02", "1996-01-04", "1d"),
...                       numpy.zeros((2,)))
array([ nan,   0.,   0.,  nan])

Additional checks raise errors in case of non-matching shapes or time information:

>>> with TestIO():
...     obs.adjust_series(Timegrid("1996-01-01", "1996-01-05", "1d"),
...                       numpy.zeros((5, 2)))   
Traceback (most recent call last):
...
RuntimeError: The shape of sequence `obs` of node `dill` is `()` but according to the external data file `...dill_obs_q.asc` it should be `(2,)`.
>>> with TestIO():
...     obs.adjust_series(Timegrid("1996-01-01", "1996-01-05", "1h"),
...                       numpy.zeros((24*5,)))   
Traceback (most recent call last):
...
RuntimeError: According to external data file `...dill_obs_q.asc`, the date time step of sequence `obs` of node `dill` is `1h` but the actual simulation time step is `1d`.
adjust_short_series(timegrid: timetools.Timegrid, values: numpy.ndarray)numpy.ndarray[source]

Adjust a short time-series to a longer time grid.

Mostly, time-series data to be read from external data files should span (at least) the whole initialisation period of a HydPy project. However, for some variables which are only used for comparison (e.g. observed runoff used for calibration), incomplete time-series might also be helpful. Method adjust_short_series() adjusts such incomplete series to the public initialisation time grid stored in module pub. It is automatically called in method adjust_series() when necessary provided that the option checkseries is disabled.

Assume the initialisation period of a HydPy project spans five days:

>>> from hydpy import pub
>>> pub.timegrids = "2000.01.10", "2000.01.15", "1d"

Prepare a node series object for observational data:

>>> from hydpy.core.sequencetools import Obs
>>> obs = Obs(None)

Prepare a test function that expects the time grid of the data and the data itself, which returns the adjusted array through calling method adjust_short_series():

>>> import numpy
>>> def test(timegrid):
...     values = numpy.ones(len(timegrid))
...     return obs.adjust_short_series(timegrid, values)

The following calls to the test function show the arrays returned for different kinds of misalignments:

>>> from hydpy import Timegrid
>>> test(Timegrid("2000.01.05", "2000.01.20", "1d"))
array([ 1.,  1.,  1.,  1.,  1.])
>>> test(Timegrid("2000.01.12", "2000.01.15", "1d"))
array([ nan,  nan,   1.,   1.,   1.])
>>> test(Timegrid("2000.01.12", "2000.01.17", "1d"))
array([ nan,  nan,   1.,   1.,   1.])
>>> test(Timegrid("2000.01.10", "2000.01.13", "1d"))
array([  1.,   1.,   1.,  nan,  nan])
>>> test(Timegrid("2000.01.08", "2000.01.13", "1d"))
array([  1.,   1.,   1.,  nan,  nan])
>>> test(Timegrid("2000.01.12", "2000.01.13", "1d"))
array([ nan,  nan,   1.,  nan,  nan])
>>> test(Timegrid("2000.01.05", "2000.01.10", "1d"))
array([ nan,  nan,  nan,  nan,  nan])
>>> test(Timegrid("2000.01.05", "2000.01.08", "1d"))
array([ nan,  nan,  nan,  nan,  nan])
>>> test(Timegrid("2000.01.15", "2000.01.18", "1d"))
array([ nan,  nan,  nan,  nan,  nan])
>>> test(Timegrid("2000.01.16", "2000.01.18", "1d"))
array([ nan,  nan,  nan,  nan,  nan])

After enabling option usedefaultvalues, the missing values are initialised with zero instead of nan:

>>> with pub.options.usedefaultvalues(True):
...     test(Timegrid("2000.01.12", "2000.01.17", "1d"))
array([ 0.,  0.,  1.,  1.,  1.])
check_completeness()None[source]

Raise a RuntimeError if the series contains at least one nan value and if the option checkseries is enabled.

>>> from hydpy import pub
>>> pub.timegrids = "2000-01-01", "2000-01-11", "1d"
>>> from hydpy.core.sequencetools import StateSequence, StateSequences
>>> class Seq(StateSequence):
...     NDIM = 0
...     NUMERIC = False
>>> class StateSequences(StateSequences):
...     CLASSES = (Seq,)
>>> seq = Seq(StateSequences(None))
>>> seq.__hydpy__connect_variable2subgroup__()
>>> seq.activate_ram()
>>> seq.check_completeness()
Traceback (most recent call last):
...
RuntimeError: The series array of sequence `seq` contains 10 nan values.
>>> seq.series = 1.0
>>> seq.check_completeness()
>>> seq.series[3] = numpy.nan
>>> seq.check_completeness()
Traceback (most recent call last):
...
RuntimeError: The series array of sequence `seq` contains 1 nan value.
>>> with pub.options.checkseries(False):
...     seq.check_completeness()
save_ext()None[source]

Write the internal data into an external data file.

Method save_ext() only calls method save_file() of class SequenceManager passing itself as the only argument. Hence, see the documentation on class the SequenceManager for further information. The following example only shows the error messages when save_file() is missing due to incomplete project configurations:

>>> from hydpy.core.sequencetools import StateSequence
>>> StateSequence(None).save_ext()
Traceback (most recent call last):
...
hydpy.core.exceptiontools.AttributeNotReady: While trying to save the external time-series data of `statesequence`, the following error occurred: Attribute sequencemanager of module `pub` is not defined at the moment.
save_mean(*args, **kwargs)None[source]

Average the time-series date with method average_series() of class IOSequence and write the result to file using method save_file() of class SequenceManager.

The main documentation on class SequenceManager provides some examples.

average_series(*args, **kwargs)hydpy.core.sequencetools.InfoArray[source]

Average the actual time-series of the Variable object for all time points.

Method average_series() works similarly as method average_values() of class Variable, from which we borrow some examples. However, firstly, we have to prepare a Timegrids object to define the series length:

>>> from hydpy import pub
>>> pub.timegrids = "2000-01-01", "2000-01-04", "1d"

As shown for method average_values(), for 0-dimensional IOSequence objects the result of method average_series() equals series itself:

>>> from hydpy.core.sequencetools import StateSequence, StateSequences
>>> class SoilMoisture(StateSequence):
...     NDIM = 0
...     NUMERIC = False
>>> class StateSequences(StateSequences):
...     CLASSES = (SoilMoisture,)
>>> sm = SoilMoisture(StateSequences(None))
>>> sm.__hydpy__connect_variable2subgroup__()
>>> sm.activate_ram()
>>> import numpy
>>> sm.series = numpy.array([190.0, 200.0, 210.0])
>>> sm.average_series()
InfoArray([ 190.,  200.,  210.])

For IOSequence objects with an increased dimensionality, we require a weighting parameter:

>>> SoilMoisture.NDIM = 1
>>> sm.shape = 3
>>> sm.activate_ram()
>>> sm.series = (
...     [190.0, 390.0, 490.0],
...     [200.0, 400.0, 500.0],
...     [210.0, 410.0, 510.0])
>>> from hydpy.core.parametertools import Parameter
>>> class Area(Parameter):
...     NDIM = 1
...     shape = (3,)
...     value = numpy.array([1.0, 1.0, 2.0])
>>> area = Area(None)
>>> SoilMoisture.refweights = property(lambda self: area)
>>> sm.average_series()
InfoArray([ 390.,  400.,  410.])

The documentation on method average_values() provides many examples of how to use different masks in different ways. Here, we only show the results of method average_series() for a mask selecting the first two entries, for a mask selecting no entry at all, and for an ill-defined mask:

>>> from hydpy.core.masktools import DefaultMask
>>> class Soil(DefaultMask):
...     @classmethod
...     def new(cls, variable, **kwargs):
...         return cls.array2mask(maskvalues)
>>> SoilMoisture.mask = Soil()
>>> maskvalues = [True, True, False]
>>> sm.average_series()
InfoArray([ 290.,  300.,  310.])
>>> maskvalues = [False, False, False]
>>> sm.average_series()
nan
>>> maskvalues = [True, True]
>>> sm.average_series()
Traceback (most recent call last):
...
IndexError: While trying to calculate the mean value of the internal time-series of sequence `soilmoisture`, the following error occurred: While trying to access the value(s) of variable `area` with key `[ True  True]`, the following error occurred: boolean index did not match indexed array along dimension 0; dimension is 3 but corresponding boolean dimension is 2
aggregate_series(*args, **kwargs)hydpy.core.sequencetools.InfoArray[source]

Aggregate time-series data based on the actual aggregation_ext attribute of IOSequence subclasses.

We prepare some nodes and elements with the help of method prepare_io_example_1() and select a 1-dimensional flux sequence of type NKor as an example:

>>> from hydpy.examples import prepare_io_example_1
>>> nodes, elements = prepare_io_example_1()
>>> seq = elements.element3.model.sequences.fluxes.nkor

If aggregation_ext is none, the original time-series values are returned:

>>> seq.aggregation_ext
'none'
>>> seq.aggregate_series()
InfoArray([[ 24.,  25.,  26.],
           [ 27.,  28.,  29.],
           [ 30.,  31.,  32.],
           [ 33.,  34.,  35.]])

If aggregation_ext is mean, method aggregate_series() is called:

>>> seq.aggregation_ext = "mean"
>>> seq.aggregate_series()
InfoArray([ 25.,  28.,  31.,  34.])

In case the state of the sequence is invalid:

>>> seq.aggregation_ext = "nonexistent"
>>> seq.aggregate_series()
Traceback (most recent call last):
...
RuntimeError: Unknown aggregation mode `nonexistent` for sequence `nkor` of element `element3`.

The following technical test confirms the propr passing of all potential positional and keyword arguments

>>> seq.aggregation_ext = "mean"
>>> from unittest import mock
>>> seq.average_series = mock.MagicMock()
>>> _ = seq.aggregate_series(1, x=2)
>>> seq.average_series.assert_called_with(1, x=2)
abstract property descr_sequence

Description of the Sequence_ object and its context.

abstract property descr_device

Description of the Device object the Sequence_ object belongs to.

name: str = 'iosequence'
unit: str = '?'
class hydpy.core.sequencetools.ModelSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.Sequence_[hydpy.core.sequencetools.ModelSequencesType, hydpy.core.variabletools.FastAccessType]

Base class for sequences to be handled by Model objects.

property descr_sequence

Description of the ModelSequence object itself and the SubSequences group it belongs to.

>>> from hydpy import prepare_model
>>> from hydpy.models import test_v1
>>> model = prepare_model(test_v1)
>>> model.sequences.fluxes.q.descr_sequence
'flux_q'
property descr_model

Description of the Model the ModelSequence object belongs to.

>>> from hydpy import prepare_model
>>> from hydpy.models import test, test_v1
>>> model = prepare_model(test)
>>> model.sequences.fluxes.q.descr_model
'test'
>>> model = prepare_model(test_v1)
>>> model.sequences.fluxes.q.descr_model
'test_v1'
property descr_device

Description of the Element object the ModelSequence object belongs to.

>>> from hydpy import prepare_model, Element
>>> element = Element("test_element_1")
>>> from hydpy.models import test_v1
>>> model = prepare_model(test_v1)
>>> model.sequences.fluxes.q.descr_device
'?'
>>> element.model = model
>>> model.sequences.fluxes.q.descr_device
'test_element_1'
name: str = 'modelsequence'
unit: str = '?'
NUMERIC: bool
NDIM: int
subvars: SubVariablesType
class hydpy.core.sequencetools.ModelIOSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.ModelSequence[hydpy.core.sequencetools.ModelIOSequencesType, hydpy.core.sequencetools.FastAccessIOSequenceType], hydpy.core.sequencetools.IOSequence[hydpy.core.sequencetools.ModelIOSequencesType, hydpy.core.sequencetools.FastAccessIOSequenceType]

Base class for sequences with input/output functionalities to be handled by Model objects.

name: str = 'modeliosequence'
unit: str = '?'
NUMERIC: bool
NDIM: int
subvars: SubVariablesType
class hydpy.core.sequencetools.InputSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.ModelIOSequence[hydpy.core.sequencetools.InputSequences, hydpy.core.sequencetools.FastAccessInputSequence]

Base class for input sequences of Model objects.

InputSequence objects provide their master model with input data, which is possible in two ways: either by providing their individually managed data (usually read from file) or data shared with an input node (usually calculated by another model). This flexibility allows, for example, to let application model hland_v1 read already preprocessed precipitation time-series or to couple it with application model conv_v001, which interpolates precipitation during the simulation run.

The second mechanism (coupling InputSequence objects with input nodes) is rather new, and we might adjust the relevant interfaces in the future. As soon as we finally settled things, we improve the following example and place it more prominently. In short, it shows that working with both types of input data sources at the same time works well and that the different deploymode options are supported:

>>> from hydpy import Element, FusedVariable, HydPy, Node, print_values, pub, TestIO
>>> from hydpy.inputs import  hland_T, hland_P
>>> hp = HydPy("LahnH")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> node_t = Node("node_t", variable=hland_T)
>>> node_p = Node("node_p", variable=FusedVariable("Precip", hland_P))
>>> node_q = Node("node_q")
>>> land_dill = Element("land_dill",
...                     inputs=[node_t, node_p],
...                     outlets=node_q)
>>> from hydpy.examples import prepare_full_example_1
>>> prepare_full_example_1()
>>> import os
>>> with TestIO():
...     os.chdir("LahnH/control/default")
...     with open("land_dill.py") as controlfile:
...         exec(controlfile.read(), {}, locals())
...     parameters.update()
...     land_dill.model = model
>>> model.sequences.inputs.t.inputflag
True
>>> model.sequences.inputs.p.inputflag
True
>>> model.sequences.inputs.epn.inputflag
False
>>> hp.update_devices(nodes=[node_t, node_p, node_q], elements=land_dill)
>>> hp.prepare_inputseries()
>>> hp.prepare_fluxseries()
>>> with TestIO():
...     hp.load_inputseries()
>>> hp.nodes.prepare_allseries()
>>> node_t.deploymode = "oldsim"
>>> node_t.sequences.sim.series = 1.0, 2.0, 3.0, 4.0, 5.0
>>> node_p.deploymode = "obs"
>>> node_p.sequences.obs.series = 0.0, 4.0, 0.0, 8.0, 0.0
>>> hp.simulate()
>>> print_values(model.sequences.inputs.t.series)
1.0, 2.0, 3.0, 4.0, 5.0
>>> print_values(model.sequences.fluxes.tc.series[:, 0])
2.05, 3.05, 4.05, 5.05, 6.05
>>> print_values(model.sequences.inputs.p.series)
0.0, 4.0, 0.0, 8.0, 0.0
>>> print_values(model.sequences.fluxes.pc.series[:, 0])
0.0, 3.441339, 0.0, 6.882678, 0.0
>>> print_values(model.sequences.inputs.epn.series)
0.285483, 0.448182, 0.302786, 0.401946, 0.315023
>>> print_values(model.sequences.fluxes.epc.series[:, 0])
0.314763, 0.524569, 0.46086, 0.689852, 0.630047
filetype_ext: ClassVar[_FileType]

Ending of the external data file.

Attribute filetype_ext is connected with attribute inputfiletype of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.inputfiletype
>>> SequenceManager.inputfiletype = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import InputSequence
>>> sequence = InputSequence(None)
>>> sequence.filetype_ext
'global'
>>> sequence.filetype_ext = "local"
>>> sequence.filetype_ext
'local'
>>> del sequence.filetype_ext
>>> sequence.filetype_ext
'global'
>>> SequenceManager.inputfiletype = temp
dirpath_ext: ClassVar[_DirPathProperty]

Absolute path of the directory of the external data file.

Attribute dirpath_ext is connected with attribute inputdirpath of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.inputdirpath
>>> SequenceManager.inputdirpath = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import InputSequence
>>> sequence = InputSequence(None)
>>> sequence.dirpath_ext
'global'
>>> sequence.dirpath_ext = "local"
>>> sequence.dirpath_ext
'local'
>>> del sequence.dirpath_ext
>>> sequence.dirpath_ext
'global'
>>> SequenceManager.inputdirpath = temp
aggregation_ext: ClassVar[_AggregationProperty]

Type of aggregation performed when writing the time-series data to an external data file.

Attribute aggregation_ext is connected with attribute inputaggregation of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.inputaggregation
>>> SequenceManager.inputaggregation = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import InputSequence
>>> sequence = InputSequence(None)
>>> sequence.aggregation_ext
'global'
>>> sequence.aggregation_ext = "local"
>>> sequence.aggregation_ext
'local'
>>> del sequence.aggregation_ext
>>> sequence.aggregation_ext
'global'
>>> SequenceManager.inputaggregation = temp
overwrite_ext: ClassVar[_OverwriteProperty]

True/False flag indicating if overwriting an existing data file is allowed or not.

Attribute overwrite_ext is connected with attribute inputoverwrite of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.inputoverwrite
>>> SequenceManager.inputoverwrite = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import InputSequence
>>> sequence = InputSequence(None)
>>> sequence.overwrite_ext
'global'
>>> sequence.overwrite_ext = "local"
>>> sequence.overwrite_ext
'local'
>>> del sequence.overwrite_ext
>>> sequence.overwrite_ext
'global'
>>> SequenceManager.inputoverwrite = temp
set_pointer(double: hydpy.cythons.autogen.pointerutils.Double)None[source]

Prepare a pointer referencing the given Double object.

Method set_pointer() should be of relevance for framework developers and eventually for some model developers only.

property inputflag

A flag telling if the actual InputSequence object queries its data from an input node (True) or uses individually managed data, usually read from a data file (False).

See the main documentation on class InputSequence for further information.

name: str = 'inputsequence'
unit: str = '?'
NUMERIC: bool
NDIM: int
subvars: SubVariablesType
class hydpy.core.sequencetools.OutputSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.ModelIOSequence[hydpy.core.sequencetools.OutputSequencesType, hydpy.core.sequencetools.FastAccessOutputSequence]

Base class for FluxSequence and StateSequence.

OutputSequence subclasses implement an optional output mechanism. Generally, as all instances of ModelSequence subclasses, output sequences handle values calculated within a simulation time step. With an activated outputflag, they also pass their internal values to an output node (see the documentation on class Element), which makes them accessible to other models.

This output mechanism (coupling OutputSequence objects with output nodes) is rather new, and we might adjust the relevant interfaces in the future. Additionally, it works for 0-dimensional output sequences only so far. As soon as we finally settled things, we improve the following example and place it more prominently. In short, it shows that everything works well for the different deploymode options:

>>> from hydpy import Element, HydPy, Node, print_values, pub, Selection, TestIO
>>> from hydpy.outputs import hland_Perc, hland_Q0, hland_Q1, hland_UZ
>>> hp = HydPy("LahnH")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> node_q0 = Node("node_q0", variable=hland_Q0)
>>> node_q1 = Node("node_q1", variable=hland_Q1)
>>> node_perc = Node("node_perc", variable=hland_Perc)
>>> node_uz = Node("node_uz", variable=hland_UZ)
>>> node_q = Node("node_q")
>>> land_dill = Element("land_dill",
...                     outlets=node_q,
...                     outputs=[node_q0, node_q1, node_perc, node_uz])
>>> from hydpy.examples import prepare_full_example_1
>>> prepare_full_example_1()
>>> import os
>>> with TestIO():
...     os.chdir("LahnH/control/default")
...     with open("land_dill.py") as controlfile:
...         exec(controlfile.read(), {}, locals())
...     parameters.update()
...     land_dill.model = model
>>> model.sequences.fluxes.q0.outputflag
True
>>> model.sequences.fluxes.q1.outputflag
True
>>> model.sequences.fluxes.perc.outputflag
True
>>> model.sequences.fluxes.qt.outputflag
False
>>> model.sequences.states.uz.outputflag
True
>>> model.sequences.states.lz.outputflag
False
>>> hp.update_devices(nodes=[node_q0, node_q1, node_perc, node_uz],
...                   elements=land_dill)
>>> with TestIO():
...     hp.load_conditions()
>>> hp.prepare_inputseries()
>>> with TestIO():
...     hp.load_inputseries()
>>> hp.prepare_fluxseries()
>>> hp.prepare_stateseries()
>>> hp.nodes.prepare_allseries()
>>> node_q0.deploymode = "oldsim"
>>> node_q0.sequences.sim.series = 1.0
>>> node_q0.sequences.obs.series = 2.0
>>> node_q1.deploymode = "obs"
>>> node_q1.sequences.obs.series = 3.0
>>> node_perc.deploymode = "newsim"
>>> node_perc.sequences.obs.series = 4.0
>>> node_uz.sequences.obs.series = 5.0
>>> hp.simulate()
>>> print_values(node_q0.sequences.sim.series)
1.0, 1.0, 1.0, 1.0, 1.0
>>> print_values(node_q0.sequences.obs.series)
2.0, 2.0, 2.0, 2.0, 2.0
>>> print_values(model.sequences.fluxes.q1.series)
0.530696, 0.539661, 0.548003, 0.555721, 0.562883
>>> print_values(node_q1.sequences.sim.series)
0.530696, 0.539661, 0.548003, 0.555721, 0.562883
>>> print_values(node_q1.sequences.obs.series)
3.0, 3.0, 3.0, 3.0, 3.0
>>> print_values(model.sequences.fluxes.perc.series)
0.692545, 0.689484, 0.687425, 0.684699, 0.682571
>>> print_values(node_perc.sequences.sim.series)
0.692545, 0.689484, 0.687425, 0.684699, 0.682571
>>> print_values(node_perc.sequences.obs.series)
4.0, 4.0, 4.0, 4.0, 4.0
>>> print_values(model.sequences.states.uz.series)
5.620222, 4.359519, 3.33013, 2.450124, 1.66734
>>> print_values(node_uz.sequences.sim.series)
5.620222, 4.359519, 3.33013, 2.450124, 1.66734
>>> print_values(node_uz.sequences.obs.series)
5.0, 5.0, 5.0, 5.0, 5.0
set_pointer(double: hydpy.cythons.autogen.pointerutils.Double)None[source]

Prepare a pointer referencing the given Double object.

Method set_pointer() should be of relevance for framework developers and eventually for some model developers only.

property outputflag

A flag telling if the actual OutputSequence object passes its data to an output node (True) or not (False).

See the main documentation on class OutputSequence for further information.

name: str = 'outputsequence'
unit: str = '?'
NUMERIC: bool
NDIM: int
subvars: SubVariablesType
filetype_ext: ClassVar[_FileType]
dirpath_ext: ClassVar[_DirPathProperty]
aggregation_ext: ClassVar[_AggregationProperty]
overwrite_ext: ClassVar[_OverwriteProperty]
class hydpy.core.sequencetools.FluxSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.OutputSequence[hydpy.core.sequencetools.FluxSequences]

Base class for flux sequences of Model objects.

filetype_ext: ClassVar[_FileType]

Ending of the external data file.

Attribute filetype_ext is connected with attribute fluxfiletype of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.fluxfiletype
>>> SequenceManager.fluxfiletype = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import FluxSequence
>>> sequence = FluxSequence(None)
>>> sequence.filetype_ext
'global'
>>> sequence.filetype_ext = "local"
>>> sequence.filetype_ext
'local'
>>> del sequence.filetype_ext
>>> sequence.filetype_ext
'global'
>>> SequenceManager.fluxfiletype = temp
dirpath_ext: ClassVar[_DirPathProperty]

Absolute path of the directory of the external data file.

Attribute dirpath_ext is connected with attribute fluxdirpath of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.fluxdirpath
>>> SequenceManager.fluxdirpath = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import FluxSequence
>>> sequence = FluxSequence(None)
>>> sequence.dirpath_ext
'global'
>>> sequence.dirpath_ext = "local"
>>> sequence.dirpath_ext
'local'
>>> del sequence.dirpath_ext
>>> sequence.dirpath_ext
'global'
>>> SequenceManager.fluxdirpath = temp
aggregation_ext: ClassVar[_AggregationProperty]

Type of aggregation performed when writing the time-series data to an external data file.

Attribute aggregation_ext is connected with attribute fluxaggregation of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.fluxaggregation
>>> SequenceManager.fluxaggregation = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import FluxSequence
>>> sequence = FluxSequence(None)
>>> sequence.aggregation_ext
'global'
>>> sequence.aggregation_ext = "local"
>>> sequence.aggregation_ext
'local'
>>> del sequence.aggregation_ext
>>> sequence.aggregation_ext
'global'
>>> SequenceManager.fluxaggregation = temp
overwrite_ext: ClassVar[_OverwriteProperty]

True/False flag indicating if overwriting an existing data file is allowed or not.

Attribute overwrite_ext is connected with attribute fluxoverwrite of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.fluxoverwrite
>>> SequenceManager.fluxoverwrite = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import FluxSequence
>>> sequence = FluxSequence(None)
>>> sequence.overwrite_ext
'global'
>>> sequence.overwrite_ext = "local"
>>> sequence.overwrite_ext
'local'
>>> del sequence.overwrite_ext
>>> sequence.overwrite_ext
'global'
>>> SequenceManager.fluxoverwrite = temp
property shape

A tuple containing the actual lengths of all dimensions.

FluxSequence objects come with some additional fastaccess attributes, which should be of interest for framework developers only. However, model developers should note that we did implement only 0-dimensional FluxSequence subclasses with a True NUMERIC flag so far. Hence, we still need to prove the complete functionality of our design of 1-dimensional FluxSequence subclasses with a True NUMERIC flag.

One example of a 0-dimensional sequence is the results array, handling the (intermediate or final) calculation results for flux sequence Inflow of the dam model:

>>> from hydpy import prepare_model, print_values, pub
>>> model = prepare_model("dam_v001")
>>> inflow = model.sequences.fluxes.inflow
>>> print_values(inflow.fastaccess._inflow_results)
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0

We now show the still not thoroughly tested functionality of 1-dimensional numerical flux sequences by changing the dimensionality of class Inflow and working in pure Python mode. Now, the results attribute is None initially, as property numericshape is unknown. However, setting the shape attribute of FluxSequence objects prepares all “fastaccess attributes” automatically:

>>> from hydpy.models.dam.dam_fluxes import Inflow
>>> Inflow.NDIM = 1
>>> with pub.options.usecython(False):
...     model = prepare_model("dam_v001")
>>> inflow = model.sequences.fluxes.inflow
>>> inflow.fastaccess._inflow_results
>>> inflow.shape = (2,)
>>> inflow.shape
(2,)
>>> inflow.fastaccess._inflow_results.shape
(11, 2)
>>> Inflow.NDIM = 0
name: str = 'fluxsequence'
unit: str = '?'
NUMERIC: bool
NDIM: int
subvars: SubVariablesType
class hydpy.core.sequencetools.ConditionSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.ModelSequence[hydpy.core.sequencetools.ModelSequencesType, hydpy.core.variabletools.FastAccessType]

Base class for StateSequence and LogSequence.

Class ConditionSequence should not be subclassed by model developers directly. Inherit from StateSequence or LogSequence instead.

trim(lower=None, upper=None)[source]

Apply trim() of module variabletools.

reset()[source]

Reset the value of the actual StateSequence or LogSequence object to the last value defined by “calling” the object.

We use the lland_v2 application model, which handles sequences derived from StateSequence (taking Inzp as an example) and from LogSequence (taking WET0 as an example):

>>> from hydpy import prepare_model, pub
>>> model = prepare_model("lland_v2")

After defining their shapes, both sequences contain nan values:

>>> inzp = model.sequences.states.inzp
>>> inzp.shape = (2,)
>>> inzp
inzp(nan, nan)
>>> wet0 = model.sequences.logs.wet0
>>> wet0.shape = 2
>>> wet0
wet0([[nan, nan]])

Before “calling” the sequences, method reset() does nothing:

>>> inzp.values = 0.0
>>> inzp.reset()
>>> inzp
inzp(0.0, 0.0)
>>> wet0.values = 0.0
>>> wet0.reset()
>>> wet0
wet0([[0.0, 0.0]])

After “calling” the sequences, method reset() reuses the respective arguments:

>>> with pub.options.warntrim(False):
...     inzp(0.0, 1.0)
>>> inzp.values = 0.0
>>> inzp
inzp(0.0, 0.0)
>>> with pub.options.warntrim(False):
...     inzp.reset()
>>> inzp
inzp(0.0, 1.0)
>>> wet0(1.0, 2.0)
>>> wet0.values = 3.0
>>> wet0
wet0([[3.0, 3.0]])
>>> wet0.reset()
>>> wet0
wet0([[1.0, 2.0]])
name: str = 'conditionsequence'
unit: str = '?'
class hydpy.core.sequencetools.StateSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.OutputSequence[hydpy.core.sequencetools.StateSequences], hydpy.core.sequencetools.ConditionSequence[hydpy.core.sequencetools.StateSequences, hydpy.core.sequencetools.FastAccessOutputSequence]

Base class for state sequences of Model objects.

Each StateSequence object is capable in handling states at two different “time points”: at the beginning of a simulation step via property old and the end of a simulation step via property new. These properties are reflected by two different fastaccess attributes. fastaccess_new is an alias for the standard fastaccess attribute storing the customary information. fastaccess_old is an additional feature for storing the supplemental information.

We demonstrate the above explanations using state sequence SM of base model hland_v1 with a shape of two:

>>> from hydpy import prepare_model
>>> model = prepare_model("hland", "1d")
>>> model.parameters.control.fc.shape = (2,)
>>> model.parameters.control.fc = 100.0
>>> sm = model.sequences.states.sm
>>> sm.shape = (2,)

Initially, no values are available at all:

>>> sm
sm(nan, nan)
>>> sm.values
array([ nan,  nan])
>>> sm.new
array([ nan,  nan])
>>> sm.old
array([ nan,  nan])

The typical way to define state values, especially within condition files, is to “call” state sequence objects, which sets both the “old” and the “new” states to the given value(s):

>>> sm(1.0)
>>> sm.values
array([ 1.,  1.])
>>> sm.new
array([ 1.,  1.])
>>> sm.old
array([ 1.,  1.])

Alternatively, one can assign values to property new or property old (note that using new is identical with using the value property):

>>> sm.new = 2.0, 3.0
>>> sm
sm(2.0, 3.0)
>>> sm.values
array([ 2.,  3.])
>>> sm.new
array([ 2.,  3.])
>>> sm.old
array([ 1.,  1.])
>>> sm.old = 200.0
>>> sm
sm(2.0, 3.0)
>>> sm.values
array([ 2.,  3.])
>>> sm.new
array([ 2.,  3.])
>>> sm.old
array([ 200.,  200.])

Assigning problematic values to property old results in very similar error messages as assigning problematic values to property value:

>>> sm.old = 1.0, 2.0, 3.0
Traceback (most recent call last):
...
ValueError: While trying to set the old value(s) of state sequence `sm`, the following error occurred: While trying to convert the value(s) `(1.0, 2.0, 3.0)` to a numpy ndarray with shape `(2,)` and type `float`, the following error occurred: could not broadcast input array from shape (3,) into shape (2,)

Just for completeness: Method new2old() effectively takes the new values as old ones, but more efficiently than using the properties new and old, as it used during simulation runs (in fact, the Python method new2old() is usually replaced by model-specific, cythonized version when working in Cython mode):

>>> sm.new2old()
>>> sm.values
array([ 2.,  3.])
>>> sm.new
array([ 2.,  3.])
>>> sm.old
array([ 2.,  3.])
NOT_DEEPCOPYABLE_MEMBERS: Tuple[str, ] = ('subseqs', 'fastaccess_old', 'fastaccess_new')
filetype_ext: ClassVar[_FileType]

Ending of the external data file.

Attribute filetype_ext is connected with attribute statefiletype of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.statefiletype
>>> SequenceManager.statefiletype = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import StateSequence
>>> sequence = StateSequence(None)
>>> sequence.filetype_ext
'global'
>>> sequence.filetype_ext = "local"
>>> sequence.filetype_ext
'local'
>>> del sequence.filetype_ext
>>> sequence.filetype_ext
'global'
>>> SequenceManager.statefiletype = temp
dirpath_ext: ClassVar[_DirPathProperty]

Absolute path of the directory of the external data file.

Attribute dirpath_ext is connected with attribute statedirpath of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.statedirpath
>>> SequenceManager.statedirpath = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import StateSequence
>>> sequence = StateSequence(None)
>>> sequence.dirpath_ext
'global'
>>> sequence.dirpath_ext = "local"
>>> sequence.dirpath_ext
'local'
>>> del sequence.dirpath_ext
>>> sequence.dirpath_ext
'global'
>>> SequenceManager.statedirpath = temp
aggregation_ext: ClassVar[_AggregationProperty]

Type of aggregation performed when writing the time-series data to an external data file.

Attribute aggregation_ext is connected with attribute stateaggregation of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.stateaggregation
>>> SequenceManager.stateaggregation = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import StateSequence
>>> sequence = StateSequence(None)
>>> sequence.aggregation_ext
'global'
>>> sequence.aggregation_ext = "local"
>>> sequence.aggregation_ext
'local'
>>> del sequence.aggregation_ext
>>> sequence.aggregation_ext
'global'
>>> SequenceManager.stateaggregation = temp
overwrite_ext: ClassVar[_OverwriteProperty]

True/False flag indicating if overwriting an existing data file is allowed or not.

Attribute overwrite_ext is connected with attribute stateoverwrite of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.stateoverwrite
>>> SequenceManager.stateoverwrite = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import StateSequence
>>> sequence = StateSequence(None)
>>> sequence.overwrite_ext
'global'
>>> sequence.overwrite_ext = "local"
>>> sequence.overwrite_ext
'local'
>>> del sequence.overwrite_ext
>>> sequence.overwrite_ext
'global'
>>> SequenceManager.stateoverwrite = temp
property shape

A tuple containing the actual lengths of all dimensions.

StateSequence objects come with some additional fastaccess attributes, which should be of interest for framework developers only. However, model developers should note that we did implement only 1-dimensional StateSequence subclasses with a True NUMERIC flag so far. We still need to prove the complete functionality of our design of 1-dimensional StateSequence subclasses with a True NUMERIC flag.

One example of a 0-dimensional sequence is the results array, handling the (intermediate or final) calculation results for state sequence WaterVolume of the dam model:

>>> from hydpy import prepare_model, print_values, pub
>>> model = prepare_model("dam_v001")
>>> watervolume = model.sequences.states.watervolume
>>> print_values(watervolume.fastaccess._watervolume_results)
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0

We now show the still not thoroughly tested functionality of 1-dimensional numerical state sequences by changing the dimensionality of class WaterVolume and working in pure Python mode. Now, the results attribute is None initially, as property numericshape is unknown. However, setting the shape attribute of StateSequence objects prepares all “fastaccess attributes” automatically:

>>> from hydpy.models.dam.dam_states import WaterVolume
>>> WaterVolume.NDIM = 1
>>> with pub.options.usecython(False):
...     model = prepare_model("dam_v001")
>>> watervolume = model.sequences.states.watervolume
>>> watervolume.fastaccess._watervolume_results
>>> watervolume.shape = (2,)
>>> watervolume.shape
(2,)
>>> watervolume.fastaccess._watervolume_results.shape
(11, 2)
>>> WaterVolume.NDIM = 0
property new

State(s) after calling a Model calculation method. (Alias for property value).

Property new handles, in contrast to property old, the newly calculated state values during each simulation step. It supports testing and debugging of individual Model methods but istypically irrelevant when scripting HydPy workflows.

property old

State(s) before calling a Model calculation method.

Note the similarity to property new. However, property old references the initial states of the respective simulation step, which should not be changed by Model calculation methods.

new2old()None[source]

Assign the new state values to the old values.

See the main documentation on class StateSequence for further information.

Note that method new2old() is replaced by a model-specific, cythonized method when working in Cython mode.

name: str = 'statesequence'
unit: str = '?'
class hydpy.core.sequencetools.LogSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.ConditionSequence[hydpy.core.sequencetools.LogSequences, hydpy.core.variabletools.FastAccess]

Base class for logging sequences of Model objects.

Class LogSequence serves similar purposes as class StateSequence, but is less strict in its assumptions. While StateSequence objects always handle two states (the old and the new one), LogSequence objects are supposed to remember an arbitrary or sequence-specific number of values, which can be state values but for example also flux values. A typical use case is to store “old” values of effective precipitation to calculate “new” values of direct discharge using the unit hydrograph concept in later simulation steps.

It is up to the model developer to make sure that a LogSequence subclass has the right dimensionality and shape to store the required information. By convention, the “memory” of each LogSequence should be placed on the first axis for non-scalar properties.

As StateSequence objects, LogSequence objects store relevant information to start a new simulation run where another one has ended, and are thus written into and read from condition files.

name: str = 'logsequence'
unit: str = '?'
NUMERIC: bool
NDIM: int
subvars: SubVariablesType
class hydpy.core.sequencetools.AideSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.ModelSequence[hydpy.core.sequencetools.AideSequences, hydpy.core.variabletools.FastAccess]

Base class for aide sequences of Model objects.

Aide sequences store data that is of importance only temporarily but must be shared by different calculation methods of a Model object.

name: str = 'aidesequence'
unit: str = '?'
NUMERIC: bool
NDIM: int
subvars: SubVariablesType
class hydpy.core.sequencetools.LinkSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.ModelSequence[hydpy.core.sequencetools.LinkSequencesType, hydpy.core.sequencetools.FastAccessLinkSequence]

Base class for link sequences of Model objects.

LinkSequence objects do not handle values themselves. Instead, they point to the values handled NodeSequence objects, using the functionalities provided by the Cython module pointerutils. Multiple LinkSequence objects of different application models can query and modify the same NodeSequence values, allowing different Model objects to share information and interact with each other.

A note for developers: LinkSequence subclasses must be either 0-dimensional or 1-dimensional.

Users might encounter the following exception, which is a safety measure to — as the error message suggests — prevent from segmentation faults:

>>> from hydpy.core.sequencetools import LinkSequence
>>> seq = LinkSequence(None)
>>> seq
linksequence(?)
>>> seq.value
Traceback (most recent call last):
...
AttributeError: While trying to query the value(s) of link sequence `linksequence` of element `?`, the following error occurred: Proper connections are missing (which could result in segmentation faults when using it, so please be careful).
set_pointer(double: hydpy.cythons.autogen.pointerutils.Double, idx: int = 0)None[source]

Prepare a pointer referencing the given Double object.

For 1-dimensional sequence objects, one also needs to specify the relevant index position of the pointer via argument idx.

Method set_pointer() should be of relevance for framework developers and eventually for some model developers only.

property value

The actual value(s) the LinkSequence object is pointing at.

Changing a value of a LinkSequence object seems very much like changing a value of any other Variable object. However, be aware that you are changing a value that is handled by a NodeSequence object. We demonstrate this by using the LahnH example project through invoking function prepare_full_example_2():

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

We focus on the hstream_v1 application model stream_lahn_1_lahn_2 routing inflow from node lahn_1 to node lahn_2:

>>> model = hp.elements.stream_lahn_1_lahn_2.model

The first example shows that the 0-dimensional outlet sequence Q points to the Sim sequence of node lahn_2:

>>> model.sequences.outlets.q
q(0.0)
>>> hp.nodes.lahn_2.sequences.sim = 1.0
>>> model.sequences.outlets.q
q(1.0)
>>> model.sequences.outlets.q(2.0)
>>> hp.nodes.lahn_2.sequences.sim
sim(2.0)

The second example shows that the 1-dimensional inlet sequence Q points to the Sim sequence of node lahn_1:

>>> model.sequences.inlets.q
q(0.0)
>>> hp.nodes.lahn_1.sequences.sim = 1.0
>>> model.sequences.inlets.q
q(1.0)
>>> model.sequences.inlets.q(2.0)
>>> hp.nodes.lahn_1.sequences.sim
sim(2.0)

Direct querying the values of both link sequences shows that the value of the 0-dimensional outlet sequence is scalar, of course, and that the value of the 1-dimensional inlet sequence is one entry of a vector:

>>> model.sequences.outlets.q.value
2.0
>>> model.sequences.inlets.q.values
array([ 2.])

Assigning bad data results in the standard error messages:

>>> model.sequences.outlets.q.value = 1.0, 2.0
Traceback (most recent call last):
...
ValueError: While trying to assign the value(s) (1.0, 2.0) to link sequence `q` of element `stream_lahn_1_lahn_2`, the following error occurred: 2 values are assigned to the scalar variable `q` of element `stream_lahn_1_lahn_2`.
>>> model.sequences.inlets.q.values = 1.0, 2.0
Traceback (most recent call last):
...
ValueError: While trying to assign the value(s) (1.0, 2.0) to link sequence `q` of element `stream_lahn_1_lahn_2`, the following error occurred: While trying to convert the value(s) `(1.0, 2.0)` to a numpy ndarray with shape `(1,)` and type `float`, the following error occurred: could not broadcast input array from shape (2,) into shape (1,)

In the example above, the 1-dimensional inlet sequence Q points to the value of a single NodeSequence value only. We now prepare a hbranch_v1 application model instance to show what happens when connecting a 1-dimensional LinkSequence object (Branched) with three NodeSequence objects (see the documentation of application model hbranch_v1 for more details):

>>> from hydpy import Element, Nodes, prepare_model
>>> model = prepare_model("hbranch_v1")
>>> nodes = Nodes("input1", "input2", "output1", "output2", "output3")
>>> branch = Element("branch",
...                  inlets=["input1", "input2"],
...                  outlets=["output1", "output2", "output3"])
>>> model.parameters.control.xpoints(
...     0.0, 2.0, 4.0, 6.0)
>>> model.parameters.control.ypoints(
...     output1=[0.0, 1.0, 2.0, 3.0],
...     output2=[0.0, 1.0, 0.0, 0.0],
...     output3=[0.0, 0.0, 2.0, 6.0])
>>> branch.model = model

Our third example demonstrates that each field of the values of a 1-dimensional LinkSequence objects points to another NodeSequence object:

>>> nodes.output1.sequences.sim = 1.0
>>> nodes.output2.sequences.sim = 2.0
>>> nodes.output3.sequences.sim = 3.0
>>> model.sequences.outlets.branched
branched(1.0, 2.0, 3.0)
>>> model.sequences.outlets.branched = 4.0, 5.0, 6.0
>>> nodes.output1.sequences.sim
sim(4.0)
>>> nodes.output2.sequences.sim
sim(5.0)
>>> nodes.output3.sequences.sim
sim(6.0)
property shape

A tuple containing the actual lengths of all dimensions.

Property shape of class LinkSequence works similarly as the general shape property of class Variable but you need to be extra careful due to the pointer mechanism underlying class LinkSequence. Change the shape of a link sequence for good reasons only. Please read the documentation on property value first and then see the following examples which are, again, based on the LahnH example project and application model hstream_v1:

>>> from hydpy.examples import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> model = hp.elements.stream_lahn_1_lahn_2.model

The default mechanisms of HydPy prepare both 0-dimensional and 1-dimensional link sequences with a proper shape (which, for inlet sequence Q, depends on the number of connected Node objects):

>>> model.sequences.outlets.q.shape
()
>>> model.sequences.inlets.q.shape
(1,)

Trying to set the only possible shape of 0-dimensional link sequences or to set any different shape results in the standard behaviour:

>>> model.sequences.outlets.q.shape = ()
>>> model.sequences.outlets.q.shape = (1,)
Traceback (most recent call last):
...
ValueError: While trying to set the shape of link sequence`q` of element `stream_lahn_1_lahn_2`, the following error occurred: The shape information of 0-dimensional variables as `q` of element `stream_lahn_1_lahn_2` can only be `()`, but `(1,)` is given.

Changing the shape of 1-dimensional link sequences is supported but results in losing the connection to the NodeSequence values of the respective nodes. The following exception is raised to prevent segmentation faults until proper connections are available:

>>> model.sequences.inlets.q.shape = (2,)
>>> model.sequences.inlets.q.shape
(2,)
>>> model.sequences.inlets.q.shape = 1
>>> model.sequences.inlets.q.shape
(1,)
>>> model.sequences.inlets.q
Traceback (most recent call last):
...
RuntimeError: While trying to query the value(s) of link sequence `q` of element `stream_lahn_1_lahn_2`, the following error occurred: The pointer of the actual `PPDouble` instance at index `0` requested, but not prepared yet via `set_pointer`.
>>> model.sequences.inlets.q(1.0)
Traceback (most recent call last):
...
RuntimeError: While trying to assign the value(s) 1.0 to link sequence `q` of element `stream_lahn_1_lahn_2`, the following error occurred: The pointer of the actual `PPDouble` instance at index `0` requested, but not prepared yet via `set_pointer`.

Querying the shape of a link sequence should rarely result in errors. However, if we enforce it by deleting the fastaccess attribute, we get an error message like the following:

>>> del model.sequences.inlets.q.fastaccess
>>> model.sequences.inlets.q.shape
Traceback (most recent call last):
...
AttributeError: While trying to query the shape of link sequence`q` of element `stream_lahn_1_lahn_2`, the following error occurred: 'Q' object has no attribute 'fastaccess'
name: str = 'linksequence'
unit: str = '?'
class hydpy.core.sequencetools.InletSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.LinkSequence[hydpy.core.sequencetools.InletSequences]

Base class for inlet link sequences of Model objects.

name: str = 'inletsequence'
unit: str = '?'
NUMERIC: bool
NDIM: int
subvars: SubVariablesType
class hydpy.core.sequencetools.OutletSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.LinkSequence[hydpy.core.sequencetools.OutletSequences]

Base class for outlet link sequences of Model objects.

name: str = 'outletsequence'
unit: str = '?'
NUMERIC: bool
NDIM: int
subvars: SubVariablesType
class hydpy.core.sequencetools.ReceiverSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.LinkSequence[hydpy.core.sequencetools.ReceiverSequences]

Base class for receiver link sequences of Model objects.

name: str = 'receiversequence'
unit: str = '?'
NUMERIC: bool
NDIM: int
subvars: SubVariablesType
class hydpy.core.sequencetools.SenderSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.LinkSequence[hydpy.core.sequencetools.SenderSequences]

Base class for sender link sequences of Model objects.

name: str = 'sendersequence'
unit: str = '?'
NUMERIC: bool
NDIM: int
subvars: SubVariablesType
class hydpy.core.sequencetools.NodeSequence(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.IOSequence[NodeSequences, hydpy.core.sequencetools.FastAccessNodeSequence]

Base class for all sequences to be handled by Node objects.

NDIM: int = 0
NUMERIC: bool = False
filetype_ext: ClassVar[_FileType]

Ending of the external data file.

Attribute filetype_ext is connected with attribute nodefiletype of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.nodefiletype
>>> SequenceManager.nodefiletype = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import NodeSequence
>>> sequence = NodeSequence(None)
>>> sequence.filetype_ext
'global'
>>> sequence.filetype_ext = "local"
>>> sequence.filetype_ext
'local'
>>> del sequence.filetype_ext
>>> sequence.filetype_ext
'global'
>>> SequenceManager.nodefiletype = temp
dirpath_ext: ClassVar[_DirPathProperty]

Absolute path of the directory of the external data file.

Attribute dirpath_ext is connected with attribute nodedirpath of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.nodedirpath
>>> SequenceManager.nodedirpath = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import NodeSequence
>>> sequence = NodeSequence(None)
>>> sequence.dirpath_ext
'global'
>>> sequence.dirpath_ext = "local"
>>> sequence.dirpath_ext
'local'
>>> del sequence.dirpath_ext
>>> sequence.dirpath_ext
'global'
>>> SequenceManager.nodedirpath = temp
aggregation_ext: ClassVar[_AggregationProperty]

Type of aggregation performed when writing the time-series data to an external data file.

Attribute aggregation_ext is connected with attribute nodeaggregation of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.nodeaggregation
>>> SequenceManager.nodeaggregation = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import NodeSequence
>>> sequence = NodeSequence(None)
>>> sequence.aggregation_ext
'global'
>>> sequence.aggregation_ext = "local"
>>> sequence.aggregation_ext
'local'
>>> del sequence.aggregation_ext
>>> sequence.aggregation_ext
'global'
>>> SequenceManager.nodeaggregation = temp
overwrite_ext: ClassVar[_OverwriteProperty]

True/False flag indicating if overwriting an existing data file is allowed or not.

Attribute overwrite_ext is connected with attribute nodeoverwrite of class SequenceManager, as shown by the following technical example (see the documentation on class IOSequence for some explanations on the usage of this and similar properties of IOSequence subclasses):

>>> from hydpy.core.filetools import SequenceManager
>>> temp = SequenceManager.nodeoverwrite
>>> SequenceManager.nodeoverwrite = "global"
>>> from hydpy import pub
>>> pub.sequencemanager = SequenceManager()
>>> from hydpy.core.sequencetools import NodeSequence
>>> sequence = NodeSequence(None)
>>> sequence.overwrite_ext
'global'
>>> sequence.overwrite_ext = "local"
>>> sequence.overwrite_ext
'local'
>>> del sequence.overwrite_ext
>>> sequence.overwrite_ext
'global'
>>> SequenceManager.nodeoverwrite = temp
property initinfo

Return a Double instead of a float object as the first tuple entry.

property descr_sequence

Description of the NodeSequence object including the variable to be represented.

>>> from hydpy import Node
>>> Node("test_node_1", "T").sequences.sim.descr_sequence
'sim_t'
>>> from hydpy import FusedVariable
>>> from hydpy.inputs import hland_T, lland_TemL
>>> Temp = FusedVariable("Temp", hland_T, lland_TemL)
>>> Node("test_node_2", Temp).sequences.sim.descr_sequence
'sim_temp'
property descr_device

Description of the Node object the NodeSequence object belongs to.

>>> from hydpy import Node
>>> Node("test_node_2").sequences.sim.descr_device
'test_node_2'
property value

The actual sequence value.

For framework users, property value of class NodeSequence works as usual and explained in the documentation on property shape of class Variable. However, framework developers should note that NodeSequence objects use Double objects for storing their values and making them accessible to PDouble and PPDouble objects as explained in detail in the documentation on class LinkSequence. For safety reasons, this mechanism is hidden for framework users via conversions to type float:

>>> from hydpy import Node
>>> sim = Node("node").sequences.sim
>>> sim(1.0)
>>> sim
sim(1.0)
>>> sim.value
1.0
>>> sim.fastaccess.sim
Double(1.0)
>>> sim.value = 2.0
>>> sim
sim(2.0)

Node sequences return errors like the following in case they receive misspecified values or ill-configured:

>>> sim.value = 1.0, 2.0
Traceback (most recent call last):
...
TypeError: While trying to assign the value `(1.0, 2.0)` to sequence `sim` of node `node`, the following error occurred: float() argument must be a string or a number, not 'tuple'
>>> del sim.fastaccess
>>> sim.value
Traceback (most recent call last):
...
AttributeError: While trying to query the value of sequence `sim` of node `node`, the following error occurred: 'Sim' object has no attribute 'fastaccess'
property seriescomplete

True/False flag indicating whether simulated or observed data is fully available or not.

We use the observation series of node dill of the LahnH project as an example:

>>> from hydpy.examples import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> obs = hp.nodes.dill.sequences.obs

When the sequence does not handle any time-series data, seriescomplete is False:

>>> obs.deactivate_ram()
>>> obs.series
Traceback (most recent call last):
...
AttributeError: Sequence `obs` of node `dill` is not requested to make any internal data available.
>>> obs.seriescomplete
False

As long as any time-series data is missing, seriescomplete is still False:

>>> obs.activate_ram()
>>> obs.series[:-1] = 1.0
>>> obs.series
InfoArray([  1.,   1.,   1.,  nan])
>>> obs.seriescomplete
False

Only with all data being not nan, seriescomplete is True:

>>> obs.series[-1] = 1.0
>>> obs.seriescomplete
True
name: str = 'nodesequence'
unit: str = '?'
class hydpy.core.sequencetools.Sim(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.IOSequence[NodeSequences, hydpy.core.sequencetools.FastAccessNodeSequence]

Class for handling those values of Node objects that are “simulated”, meaning calculated by hydrological models.

load_ext()None[source]

Read time-series data like method load_ext() of class IOSequence but with special handling of missing data.

The method’s “special handling” is to convert errors to warnings. We explain the reasons in the documentation on method load_ext() of class Obs, from which we borrow the following examples. The only differences are that method load_ext() of class Sim does not disable property memoryflag and uses the option warnmissingsimfile instead of warnmissingobsfile:

>>> from hydpy.examples import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, TestIO
>>> hp = HydPy("LahnH")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_network()
...     hp.prepare_models()
...     hp.prepare_simseries()
>>> sim = hp.nodes.dill.sequences.sim
>>> with TestIO():
...     sim.load_ext()    
Traceback (most recent call last):
...
UserWarning: While trying to load the external data of sequence `sim` of node `dill`, the following error occurred: [Errno 2] No such file or directory: '...dill_sim_q.asc'
>>> sim.series
InfoArray([ nan,  nan,  nan,  nan,  nan])
>>> sim.series = 1.0
>>> with TestIO():
...     sim.save_ext()
>>> sim.series = 0.0
>>> with TestIO():
...     sim.load_ext()
>>> sim.series
InfoArray([ 1.,  1.,  1.,  1.,  1.])
>>> import numpy
>>> sim.series[2] = numpy.nan
>>> with TestIO():
...     pub.sequencemanager.nodeoverwrite = True
...     sim.save_ext()
>>> with TestIO():
...     sim.load_ext()
Traceback (most recent call last):
...
UserWarning: While trying to load the external data of sequence `sim` of node `dill`, the following error occurred: The series array of sequence `sim` of node `dill` contains 1 nan value.
>>> sim.series
InfoArray([  1.,   1.,  nan,   1.,   1.])
>>> sim.series = 0.0
>>> with TestIO():
...     with pub.options.warnmissingsimfile(False):
...         sim.load_ext()
>>> sim.series
InfoArray([  1.,   1.,  nan,   1.,   1.])
name: str = 'sim'
unit: str = '?'
subvars: SubVariablesType
class hydpy.core.sequencetools.Obs(subvars: SubVariablesType)[source]

Bases: hydpy.core.sequencetools.IOSequence[NodeSequences, hydpy.core.sequencetools.FastAccessNodeSequence]

Class for handling those values of Node objects that are observed, meaning read from data files.

load_ext()None[source]

Read time-series data like method load_ext() of class IOSequence but with special handling of missing data.

When reading incomplete time-series data, HydPy usually raises a RuntimeError to prevent from performing erroneous calculations. For instance, this makes sense for meteorological input data, being a strict requirement for hydrological simulations. However, the same often does not hold for the time-series of Obs sequences, e.g. representing measured discharge. Measured discharge is often handled as an optional input value, or even used for comparison purposes only.

According to this reasoning, HydPy raises (at most) a UserWarning in case of missing or incomplete external time-series data of Obs sequences. The following examples show this based on the LahnH project, mainly focussing on the Obs sequence of node dill, which is ready for handling time-series data at the end of the following steps:

>>> from hydpy.examples import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, TestIO
>>> hp = HydPy("LahnH")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_network()
...     hp.prepare_models()
...     hp.prepare_obsseries()
>>> obs = hp.nodes.dill.sequences.obs
>>> obs.ramflag
True

Trying to read non-existing data raises the following warning and disables the sequence’s ability to handle time-series data:

>>> with TestIO():
...     hp.load_obsseries()    
Traceback (most recent call last):
...
UserWarning: The `memory flag` of sequence `obs` of node `dill` had to be set to `False` due to the following problem: While trying to load the external data of sequence `obs` of node `dill`, the following error occurred: [Errno 2] No such file or directory: '...dill_obs_q.asc'
>>> obs.ramflag
False

After writing a complete external data file, everything works fine:

>>> obs.activate_ram()
>>> obs.series = 1.0
>>> with TestIO():
...     obs.save_ext()
>>> obs.series = 0.0
>>> with TestIO():
...     obs.load_ext()
>>> obs.series
InfoArray([ 1.,  1.,  1.,  1.,  1.])

Reading incomplete data also results in a warning message, but does not disable the memoryflag:

>>> import numpy
>>> obs.series[2] = numpy.nan
>>> with TestIO():
...     pub.sequencemanager.nodeoverwrite = True
...     obs.save_ext()
>>> with TestIO():
...     obs.load_ext()
Traceback (most recent call last):
...
UserWarning: While trying to load the external data of sequence `obs` of node `dill`, the following error occurred: The series array of sequence `obs` of node `dill` contains 1 nan value.
>>> obs.memoryflag
True

Option warnmissingobsfile allows disabling the warning messages without altering the functionalities described above:

>>> hp.prepare_obsseries()
>>> with TestIO():
...     with pub.options.warnmissingobsfile(False):
...         hp.load_obsseries()
>>> obs.series
InfoArray([  1.,   1.,  nan,   1.,   1.])
>>> hp.nodes.lahn_1.sequences.obs.memoryflag
False
name: str = 'obs'
unit: str = '?'
subvars: SubVariablesType
class hydpy.core.sequencetools.NodeSequences(master: devicetools.Node, cls_fastaccess: Optional[Type[hydpy.core.sequencetools.FastAccessNodeSequence]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)[source]

Bases: hydpy.core.sequencetools.IOSequences[devicetools.Node, hydpy.core.sequencetools.NodeSequence, hydpy.core.sequencetools.FastAccessNodeSequence]

Base class for handling Sim and Obs sequence objects.

Basically, NodeSequences works like the different ModelSequences subclasses used for handling ModelSequence objects. The main difference is that they do not reference a Sequences object (which is only handled by Element objects but not by Node objects). Instead, they reference their master Node object via the attribute node directly:

>>> from hydpy import Node
>>> node = Node("node")
>>> node.sequences.node
Node("node", variable="Q")

The implemented methods just call the same method of the underlying fastaccess attribute, which is an instance of (a Cython extension class of) the Python class FastAccessNodeSequence.

sim: hydpy.core.sequencetools.Sim
obs: hydpy.core.sequencetools.Obs
node: devicetools.Node
load_data(idx: int)None[source]

Call method load_data() of the current fastaccess attribute.

>>> from hydpy import Node, pub
>>> with pub.options.usecython(False):
...     node = Node("node")
>>> from unittest import mock
>>> method = "hydpy.core.sequencetools.FastAccessNodeSequence.load_data"
>>> with mock.patch(method) as mocked:
...     node.sequences.load_data(5)
>>> mocked.call_args_list
[call(5)]
load_simdata(idx: int)None[source]

Call method load_simdata() of the current fastaccess attribute.

>>> from hydpy import Node, pub
>>> with pub.options.usecython(False):
...     node = Node("node")
>>> from unittest import mock
>>> method = "hydpy.core.sequencetools.FastAccessNodeSequence.load_simdata"
>>> with mock.patch(method) as mocked:
...     node.sequences.load_simdata(5)
>>> mocked.call_args_list
[call(5)]
load_obsdata(idx: int)None[source]

Call method load_obsdata() of the current fastaccess attribute.

>>> from hydpy import Node, pub
>>> with pub.options.usecython(False):
...     node = Node("node")
>>> from unittest import mock
>>> method = "hydpy.core.sequencetools.FastAccessNodeSequence.load_obsdata"
>>> with mock.patch(method) as mocked:
...     node.sequences.load_obsdata(5)
>>> mocked.call_args_list
[call(5)]
save_data(idx: int)None[source]

Call method save_data() of the current fastaccess attribute.

>>> from hydpy import Node, pub
>>> with pub.options.usecython(False):
...     node = Node("node")
>>> from unittest import mock
>>> method = "hydpy.core.sequencetools.FastAccessNodeSequence.save_data"
>>> with mock.patch(method) as mocked:
...     node.sequences.save_data(5)
>>> mocked.call_args_list
[call(5)]
save_simdata(idx: int)None[source]

Call method save_simdata() of the current fastaccess attribute.

>>> from hydpy import Node, pub
>>> with pub.options.usecython(False):
...     node = Node('node')
>>> from unittest import mock
>>> method = "hydpy.core.sequencetools.FastAccessNodeSequence.save_simdata"
>>> with mock.patch(method) as mocked:
...     node.sequences.save_simdata(5)
>>> mocked.call_args_list
[call(5)]