Exemplo n.º 1
0
 def __init__(self,
              name: str,
              nodes: devicetools.NodesConstrArg = None,
              elements: devicetools.ElementsConstrArg = None):
     self.name = str(name)
     self.nodes = devicetools.Nodes(nodes).copy()
     self.elements = devicetools.Elements(elements).copy()
Exemplo n.º 2
0
    def nodes(self):
        """A |Nodes| collection of all required nodes.

        >>> from hydpy import RiverBasinNumbers2Selection
        >>> rbns2s = RiverBasinNumbers2Selection(
        ...                            (111, 113, 1129, 11269, 1125, 11261,
        ...                             11262, 1123, 1124, 1122, 1121))

        Note that the required outlet node is added:

        >>> rbns2s.nodes
        Nodes("node_1123", "node_1125", "node_11269", "node_1129", "node_113",
              "node_outlet")

        It is both possible to change the prefix names of the nodes and
        the name of the outlet node separately:

        >>> rbns2s.node_prefix = 'b_'
        >>> rbns2s.last_node = 'l_node'
        >>> rbns2s.nodes
        Nodes("b_1123", "b_1125", "b_11269", "b_1129", "b_113", "l_node")
        """
        return (devicetools.Nodes(self.node_prefix + routers
                                  for routers in self._router_numbers) +
                devicetools.Node(self.last_node))
Exemplo n.º 3
0
 def __init__(self, element, seqs=None, inits=None):
     nodes = devicetools.Nodes()
     for connection in (element.inlets, element.outlets, element.receivers,
                        element.senders):
         nodes += connection.slaves
     for (name, node) in nodes:
         if (node in element.inlets) or (node in element.receivers):
             node.routingmode = 'oldsim'
         sim = node.sequences.sim
         sim.ramflag = True
         sim._setarray(numpy.zeros(len(pub.timegrids.init), dtype=float))
     for (name, seq) in getattr(element.model.sequences, 'inputs', ()):
         seq.ramflag = True
         seq._setarray(numpy.zeros(len(pub.timegrids.init), dtype=float))
     if seqs is None:
         seqs = []
         for subseqs in ('inputs', 'fluxes', 'states'):
             for (name, seq) in getattr(element.model.sequences, subseqs,
                                        ()):
                 seqs.append(seq)
         for (name, node) in nodes:
             seqs.append(node.sequences.sim)
     element.prepare_fluxseries()
     element.prepare_stateseries()
     self.element = element
     self.nodes = nodes
     self.seqs = seqs
     self.inits = {} if inits is None else inits
     self.model = element.model
     hydpytools.HydPy.nmb_instances = 0
     self.hp = hydpytools.HydPy()
     self.hp.updatedevices(selectiontools.Selection('test', nodes, element))
Exemplo n.º 4
0
 def extract_nodes(self):
     """Return all nodes connected to the actual element."""
     nodes = devicetools.Nodes()
     for connection in (self.element.inlets, self.element.outlets,
                        self.element.receivers, self.element.senders):
         nodes += connection.slaves
     return nodes
Exemplo n.º 5
0
 def endnodes(self):
     endnodes = devicetools.Nodes()
     for (name, node) in self.nodes:
         for (name, element) in node.exits:
             if ((element in self.elements) and
                 (node not in element.receivers)):
                 break
         else:
             endnodes += node
     return endnodes
Exemplo n.º 6
0
    def deselect_modeltypes(self, *models: ModelTypesArg) -> 'Selection':
        """Restrict the current selection to all elements not containing the
        given model types (removes all nodes).

        See the documentation on method |Selection.search_modeltypes| for
        additional information.
        """
        self.nodes = devicetools.Nodes()
        self.elements -= self.search_modeltypes(*models).elements
        return self
Exemplo n.º 7
0
    def deselect_modelclasses(self, *modelclasses):
        """Limits the current selection to all elements not containing the
        given modelclass(es).  (All nodes are removed.)

        Argument:
            * modelclass (subclass of :class:`~hydpy.core.models.Model`):
              Model type(s) as the selection criterion/criteria.
        """
        self.nodes = devicetools.Nodes()
        self.elements -= self.getby_modelclasses(*modelclasses)
        return self
Exemplo n.º 8
0
    def select_modelclasses(self, *modelclass):
        """Limits the current selection to all elements containing the
        given modelclass(es).  (All nodes are removed.)

        Argument:
            * modelclass (subclass of |Model|): Model type(s) as the
              selection criterion/criteria.
        """
        self.nodes = devicetools.Nodes()
        self.elements = self.getby_modelclasses(modelclass)
        return self
Exemplo n.º 9
0
 def endnodes(self):
     """|Nodes| object containing all |Node| objects currently handled by
     the |HydPy| object which define a downstream end point of a network."""
     endnodes = devicetools.Nodes()
     for node in self.nodes:
         for element in node.exits:
             if ((element in self.elements)
                     and (node not in element.receivers)):
                 break
         else:
             endnodes += node
     return endnodes
Exemplo n.º 10
0
    def getby_nodenames(self, *substrings):
        """Returns all nodes of the current selection with a name
        containing the given substrings(s).

        Argument:
            * substrings (:class:`str`): (Possible) Part(s) of the nodes
              name as the selection criterion/criteria.
        """
        nodes = devicetools.Nodes()
        for (name, node) in self.nodes:
            for substring in substrings:
                if substring in name:
                    nodes += node
                    break
        return nodes
Exemplo n.º 11
0
    def nodes(self) -> devicetools.Nodes:
        """A |set| containing the |Node| objects of all handled
        |Selection| objects.

        >>> from hydpy import Selection, Selections
        >>> selections = Selections(
        ...     Selection('sel1', ['node1', 'node2'], ['element1']),
        ...     Selection('sel2', ['node1', 'node3'], ['element2']))
        >>> selections.nodes
        Nodes("node1", "node2", "node3")
        """
        nodes = devicetools.Nodes()
        for selection in self:
            nodes += selection.nodes
        return nodes
Exemplo n.º 12
0
    def getby_upstream(self, device):
        """Returns the network upstream of the given starting point, including
        the starting point itself.

        Argument:
            * device (|Node| or |Element|): Lowest point to be selected.
        """
        nodes = devicetools.Nodes()
        elements = devicetools.Elements()
        if isinstance(device, devicetools.Node):
            nodes, elements = self._nextnode(device, nodes, elements)
        elif isinstance(device, devicetools.Element):
            nodes, elements = self._nextelement(device, nodes, elements)
        else:
            raise AttributeError('Pass either a `Node` or an `Element` '
                                 'instance to the function.  The given '
                                 '`device` value `%s` is of type `%s`.' %
                                 (device, type(device)))
        return nodes, elements
Exemplo n.º 13
0
    def nodes(self) -> devicetools.Nodes:
        """A |Nodes| object containing all required nodes, including the
        outlet node.

        >>> from hydpy import RiverBasinNumbers2Selection
        >>> rbns2s = RiverBasinNumbers2Selection(
        ...                            (111, 113, 1129, 11269, 1125, 11261,
        ...                             11262, 1123, 1124, 1122, 1121))
        >>> rbns2s.nodes
        Nodes("node_1123", "node_1125", "node_11269", "node_1129", "node_113",
              "node_outlet")

        It is both possible to change the prefix names of the nodes and
        the name of the outlet node separately:

        >>> rbns2s.node_prefix = "b_"
        >>> rbns2s.last_node = "l_node"
        >>> rbns2s.nodes
        Nodes("b_1123", "b_1125", "b_11269", "b_1129", "b_113", "l_node")
        """
        return devicetools.Nodes(
            self.node_prefix + routers
            for routers in self._router_numbers) + devicetools.Node(
                self.last_node)
Exemplo n.º 14
0
    def connect(self):
        """Connect the |InletSequence| and |OutletSequence| objects of
        the actual model to the |NodeSequence| objects handled by an
        arbitrary number of inlet and outlet nodes.

        To application models derived from |conv_model.Model|, you first
        need to define an |Element| connected with an arbitrary number of
        inlet and outlet nodes:

        >>> from hydpy import Element
        >>> conv = Element("conv",
        ...                inlets=["in1", "in2"],
        ...                outlets=["out1", "out2", "out3"])

        Second, you must define the inlet and outlet nodes' coordinates via
        parameter |InputCoordinates| and |OutputCoordinates|, respectively.
        In both cases, use the names of the |Node| objects as keyword arguments
        to pass the corresponding coordinates:

        >>> from hydpy.models.conv_v001 import *
        >>> parameterstep()
        >>> inputcoordinates(
        ...     in1=(0.0, 3.0),
        ...     in2=(2.0, -1.0))
        >>> outputcoordinates(
        ...     out1=(0.0, 3.0),
        ...     out2=(3.0, -2.0),
        ...     out3=(1.0, 2.0))
        >>> maxnmbinputs()
        >>> parameters.update()

        |conv| passes the current values of the inlet nodes correctly to
        the outlet nodes (note that node `in1` works with simulated values
        while node `in2` works with observed values, as we set its
        |Node.deploymode| to `obs`):

        >>> conv.model = model
        >>> conv.inlets.in1.sequences.sim = 1.0
        >>> conv.inlets.in2.deploymode = "obs"
        >>> conv.inlets.in2.sequences.obs = 2.0
        >>> model.simulate(0)
        >>> conv.outlets.out1.sequences.sim
        sim(1.0)
        >>> conv.outlets.out2.sequences.sim
        sim(2.0)
        >>> conv.outlets.out3.sequences.sim
        sim(1.0)

        When you forget a node (or misspell its name), you get the
        following error message:

        >>> outputcoordinates(
        ...     out1=(0.0, 3.0),
        ...     out2=(3.0, -2.0))
        >>> maxnmbinputs()
        >>> parameters.update()
        >>> conv.model = model
        Traceback (most recent call last):
        ...
        RuntimeError: While trying to connect model `conv_v001` of element \
`conv`, the following error occurred: The node handled by control parameter \
outputcoordinates (out1 and out2) are not the same as the outlet nodes \
handled by element conv (out1, out2, and out3).
        """
        try:
            for coordinates, sequence, nodes in (
                (
                    self.parameters.control.inputcoordinates,
                    self.sequences.inlets.inputs,
                    self.element.inlets,
                ),
                (
                    self.parameters.control.outputcoordinates,
                    self.sequences.outlets.outputs,
                    self.element.outlets,
                ),
            ):
                if nodes == devicetools.Nodes(coordinates.nodes):
                    sequence.shape = len(coordinates)
                    for idx, node in enumerate(coordinates.nodes):
                        sequence.set_pointer(
                            node.get_double(sequence.subseqs.name), idx)
                else:
                    parameternodes = objecttools.enumeration(coordinates.nodes)
                    elementnodes = objecttools.enumeration(nodes)
                    raise RuntimeError(
                        f"The node handled by control parameter "
                        f"{coordinates.name} ({parameternodes}) are not the "
                        f"same as the {sequence.subseqs.name[:-1]} nodes "
                        f"handled by element {self.element.name} "
                        f"({elementnodes}).")
        except BaseException:
            objecttools.augment_excmessage(
                f"While trying to connect model "
                f"{objecttools.elementphrase(self)}")
Exemplo n.º 15
0
def prepare_io_example_1() -> Tuple[devicetools.Nodes, devicetools.Elements]:
    """Prepare an IO example configuration for testing purposes.

    Function |prepare_io_example_1| is thought for testing the functioning
    of *HydPy* and thus should be of interest for framework developers only.
    It uses the application models |lland_v1| and |lland_v2|.  Here, we
    apply |prepare_io_example_1| and shortly discuss different aspects of
    the data it generates.

    >>> from hydpy.examples import prepare_io_example_1
    >>> nodes, elements = prepare_io_example_1()

    (1) It defines a short initialisation period of five days:

    >>> from hydpy import pub
    >>> pub.timegrids
    Timegrids("2000-01-01 00:00:00",
              "2000-01-05 00:00:00",
              "1d")

    (2) It creates a flat IO testing directory structure:

    >>> pub.sequencemanager.inputdirpath
    'inputpath'
    >>> pub.sequencemanager.fluxdirpath
    'outputpath'
    >>> pub.sequencemanager.statedirpath
    'outputpath'
    >>> pub.sequencemanager.nodedirpath
    'nodepath'
    >>> import os
    >>> from hydpy import TestIO
    >>> with TestIO():
    ...     print(sorted(filename for filename in os.listdir(".")
    ...                  if not filename.startswith("_")))
    ['inputpath', 'nodepath', 'outputpath']

    (3) It returns three |Element| objects handling either application model
    |lland_v1| or |lland_v2|, and two |Node| objects handling variables
    `Q` and `T`:

    >>> for element in elements:
    ...     print(element.name, element.model)
    element1 lland_v1
    element2 lland_v1
    element3 lland_v2
    >>> for node in nodes:
    ...     print(node.name, node.variable)
    node1 Q
    node2 T

    (4) It generates artificial time series data of the input sequence
    |lland_inputs.Nied|, the flux sequence |lland_fluxes.NKor|, and the
    state sequence |lland_states.BoWa| of each model instance, and the
    |Sim| sequence of each node instance.  For unambiguous test results,
    all generated values are unique:

    >>> nied1 = elements.element1.model.sequences.inputs.nied
    >>> nied1.series
    InfoArray([ 0.,  1.,  2.,  3.])
    >>> nkor1 = elements.element1.model.sequences.fluxes.nkor
    >>> nkor1.series
    InfoArray([[ 12.],
               [ 13.],
               [ 14.],
               [ 15.]])
    >>> bowa3 = elements.element3.model.sequences.states.bowa
    >>> bowa3.series
    InfoArray([[ 48.,  49.,  50.],
               [ 51.,  52.,  53.],
               [ 54.,  55.,  56.],
               [ 57.,  58.,  59.]])
    >>> sim2 = nodes.node2.sequences.sim
    >>> sim2.series
    InfoArray([ 64.,  65.,  66.,  67.])

    (5) All sequences carry |numpy.ndarray| objects with (deep) copies
    of the time series data for testing:

    >>> import numpy
    >>> (numpy.all(nied1.series == nied1.testarray) and
    ...  numpy.all(nkor1.series == nkor1.testarray) and
    ...  numpy.all(bowa3.series == bowa3.testarray) and
    ...  numpy.all(sim2.series == sim2.testarray))
    InfoArray(True, dtype=bool)
    >>> bowa3.series[1, 2] = -999.0
    >>> numpy.all(bowa3.series == bowa3.testarray)
    InfoArray(False, dtype=bool)
    """
    testtools.TestIO.clear()
    hydpy.pub.sequencemanager = filetools.SequenceManager()
    with testtools.TestIO():
        hydpy.pub.sequencemanager.inputdirpath = "inputpath"
        hydpy.pub.sequencemanager.fluxdirpath = "outputpath"
        hydpy.pub.sequencemanager.statedirpath = "outputpath"
        hydpy.pub.sequencemanager.nodedirpath = "nodepath"

    hydpy.pub.timegrids = "2000-01-01", "2000-01-05", "1d"

    node1 = devicetools.Node("node1")
    node2 = devicetools.Node("node2", variable="T")
    nodes = devicetools.Nodes(node1, node2)
    element1 = devicetools.Element("element1", outlets=node1)
    element2 = devicetools.Element("element2", outlets=node1)
    element3 = devicetools.Element("element3", outlets=node1)
    elements = devicetools.Elements(element1, element2, element3)

    element1.model = importtools.prepare_model("lland_v1")
    element2.model = importtools.prepare_model("lland_v1")
    element3.model = importtools.prepare_model("lland_v2")

    for idx, element in enumerate(elements):
        parameters = element.model.parameters
        parameters.control.nhru(idx + 1)
        parameters.control.lnk(lland.ACKER)
        parameters.derived.absfhru(10.0)

    # pylint: disable=not-callable
    # pylint usually understands that all options are callable
    # but, for unknown reasons, not in the following line:
    with hydpy.pub.options.printprogress(False):
        nodes.prepare_simseries()
        elements.prepare_inputseries()
        elements.prepare_fluxseries()
        elements.prepare_stateseries()
    # pylint: enable=not-callable

    def init_values(seq, value1_):
        value2_ = value1_ + len(seq.series.flatten())
        values_ = numpy.arange(value1_, value2_, dtype=float)
        seq.testarray = values_.reshape(seq.seriesshape)
        seq.series = seq.testarray.copy()
        return value2_

    value1 = 0
    for subname, seqname in zip(["inputs", "fluxes", "states"],
                                ["nied", "nkor", "bowa"]):
        for element in elements:
            subseqs = getattr(element.model.sequences, subname)
            value1 = init_values(getattr(subseqs, seqname), value1)
    for node in nodes:
        value1 = init_values(node.sequences.sim, value1)

    return nodes, elements
Exemplo n.º 16
0
 def __init__(self, name, nodes=None, elements=None):
     self.name = name
     self.nodes = devicetools.Nodes(nodes)
     self.elements = devicetools.Elements(elements)
Exemplo n.º 17
0
def prepare_io_example_1() -> Tuple[devicetools.Nodes, devicetools.Elements]:
    """Prepare an IO example configuration for testing purposes.

    Function |prepare_io_example_1| is thought for testing the functioning of *HydPy*
    and thus should be of interest for framework developers only.  It uses the
    application models |lland_v1|, |lland_v2|, and |hland_v1|.  Here, we apply
    |prepare_io_example_1| and shortly discuss different aspects of its generated data.

    >>> from hydpy.examples import prepare_io_example_1
    >>> nodes, elements = prepare_io_example_1()

    (1) It defines a short initialisation period of five days:

    >>> from hydpy import pub
    >>> pub.timegrids
    Timegrids("2000-01-01 00:00:00",
              "2000-01-05 00:00:00",
              "1d")

    (2) It prepares an empty directory for IO testing:

    >>> import os
    >>> from hydpy import repr_, TestIO
    >>> with TestIO():  # doctest: +ELLIPSIS
    ...     repr_(pub.sequencemanager.currentpath)
    ...     os.listdir("project/series/default")
    '...iotesting/project/series/default'
    []

    (3) It returns four |Element| objects handling either application model |lland_v1|
    |lland_v2|, or |hland_v1|, and two |Node| objects handling variables `Q` and `T`:

    >>> for element in elements:
    ...     print(element.name, element.model)
    element1 lland_v1
    element2 lland_v1
    element3 lland_v2
    element4 hland_v1
    >>> for node in nodes:
    ...     print(node.name, node.variable)
    node1 Q
    node2 T

    (4) It generates artificial time series data for the input sequence
    |lland_inputs.Nied|, the flux sequence |lland_fluxes.NKor|, and the state sequence
    |lland_states.BoWa| of each |lland| model instance, the state sequence
    |hland_states.SP| of the |hland_v1| model instance, and the |Sim| sequence of each
    node instance.  For precise test results, all generated values are unique:

    >>> nied1 = elements.element1.model.sequences.inputs.nied
    >>> nied1.series
    InfoArray([0., 1., 2., 3.])
    >>> nkor1 = elements.element1.model.sequences.fluxes.nkor
    >>> nkor1.series
    InfoArray([[12.],
               [13.],
               [14.],
               [15.]])
    >>> bowa3 = elements.element3.model.sequences.states.bowa
    >>> bowa3.series
    InfoArray([[48., 49., 50.],
               [51., 52., 53.],
               [54., 55., 56.],
               [57., 58., 59.]])
    >>> sim2 = nodes.node2.sequences.sim
    >>> sim2.series
    InfoArray([64., 65., 66., 67.])
    >>> sp4 = elements.element4.model.sequences.states.sp
    >>> sp4.series
    InfoArray([[[68., 69., 70.],
                [71., 72., 73.]],
    <BLANKLINE>
               [[74., 75., 76.],
                [77., 78., 79.]],
    <BLANKLINE>
               [[80., 81., 82.],
                [83., 84., 85.]],
    <BLANKLINE>
               [[86., 87., 88.],
                [89., 90., 91.]]])

    (5) All sequences carry |numpy.ndarray| objects with (deep) copies of the
    time-series data for testing:

    >>> import numpy
    >>> (numpy.all(nied1.series == nied1.testarray) and
    ...  numpy.all(nkor1.series == nkor1.testarray) and
    ...  numpy.all(bowa3.series == bowa3.testarray) and
    ...  numpy.all(sim2.series == sim2.testarray) and
    ...  numpy.all(sp4.series == sp4.testarray))
    InfoArray(True)
    >>> bowa3.series[1, 2] = -999.0
    >>> numpy.all(bowa3.series == bowa3.testarray)
    InfoArray(False)
    """
    testtools.TestIO.clear()

    hydpy.pub.projectname = "project"
    hydpy.pub.sequencemanager = filetools.SequenceManager()
    with testtools.TestIO():
        os.makedirs("project/series/default")

    hydpy.pub.timegrids = "2000-01-01", "2000-01-05", "1d"

    node1 = devicetools.Node("node1")
    node2 = devicetools.Node("node2", variable="T")
    nodes = devicetools.Nodes(node1, node2)
    element1 = devicetools.Element("element1", outlets=node1)
    element2 = devicetools.Element("element2", outlets=node1)
    element3 = devicetools.Element("element3", outlets=node1)
    element4 = devicetools.Element("element4", outlets=node1)
    elements_lland = devicetools.Elements(element1, element2, element3)
    elements = elements_lland + element4

    element1.model = importtools.prepare_model("lland_v1")
    element2.model = importtools.prepare_model("lland_v1")
    element3.model = importtools.prepare_model("lland_v2")
    element4.model = importtools.prepare_model("hland_v1")

    for idx, element in enumerate(elements_lland):
        parameters = element.model.parameters
        parameters.control.nhru(idx + 1)
        parameters.control.lnk(lland.ACKER)
        parameters.derived.absfhru(10.0)
    control = element4.model.parameters.control
    control.nmbzones(3)
    control.sclass(2)
    control.zonetype(hland.FIELD)
    control.zonearea.values = 10.0

    # pylint: disable=not-callable
    # pylint usually understands that all options are callable
    # but, for unknown reasons, not in the following line:
    with hydpy.pub.options.printprogress(False):
        nodes.prepare_simseries(allocate_ram=False)  # ToDo: add option "reset"
        nodes.prepare_simseries(allocate_ram=True)
        elements.prepare_inputseries(allocate_ram=False)
        elements.prepare_inputseries(allocate_ram=True)
        elements.prepare_factorseries(allocate_ram=False)
        elements.prepare_factorseries(allocate_ram=True)
        elements.prepare_fluxseries(allocate_ram=False)
        elements.prepare_fluxseries(allocate_ram=True)
        elements.prepare_stateseries(allocate_ram=False)
        elements.prepare_stateseries(allocate_ram=True)
    # pylint: enable=not-callable

    def init_values(seq: TestIOSequence, value1_: float) -> float:
        value2_ = value1_ + len(seq.series.flatten())
        values_ = numpy.arange(value1_, value2_, dtype=float)
        seq.testarray = values_.reshape(seq.seriesshape)
        seq.series = seq.testarray.copy()
        return value2_

    value1 = 0.0
    for subname, seqname in zip(["inputs", "fluxes", "states"],
                                ["nied", "nkor", "bowa"]):
        for element in elements_lland:
            subseqs = getattr(element.model.sequences, subname)
            value1 = init_values(getattr(subseqs, seqname), value1)
    for node in nodes:
        value1 = init_values(node.sequences.sim,
                             value1)  # type: ignore[arg-type]
    init_values(element4.model.sequences.states.sp,
                value1)  # type: ignore[arg-type]

    return nodes, elements