xmltools

This module provides features for executing HydPy workflows based on XML configuration files.

At the heart of module xmltools lies function run_simulation(), thought to be applied via a command line (see the documentation on script hyd for further information). run_simulation() expects that the HydPy project you want to work with is available in your current working directory and contains an XML configuration file (as single_run.xml in the example project folder HydPy-H-Lahn). This configuration file must agree with the XML schema HydPyConfigSingleRun.xsd, which is available in the conf subpackage and separately downloadable for each HydPy release. If you did implement new or changed existing models, you have to update this schema file. HydPy does this automatically through its setup mechanism (see the documentation on class XSDWriter).

To show how to apply run_simulation() via a command line, we first copy the HydPy-H-Lahn project into the iotesting folder by calling the function prepare_full_example_1():

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()

Running the simulation requires defining the main script (hyd.py), the function specifying the actual workflow (run_simulation), the name of the project of interest (HydPy-H-Lahn), and the name of the relevant XML configuration file (single_run.xml). We pass the required text to function run_subprocess() of module subprocess to simulate using the command line:

>>> from hydpy import run_subprocess, TestIO
>>> import subprocess
>>> with TestIO():  
...     result = run_subprocess("hyd.py run_simulation HydPy-H-Lahn single_run.xml")
Start HydPy project `HydPy-H-Lahn` (...).
Read configuration file `single_run.xml` (...).
Interpret the defined options (...).
Interpret the defined period (...).
Read all network files (...).
Activate the selected network (...).
Read the required control files (...).
Read the required condition files (...).
Read the required time series files (...).
Perform the simulation run (...).
Write the desired condition files (...).
Write the desired time series files (...).

As defined by the XML configuration file, the simulation started on the first and ended on the sixth of January 1996. The following example shows the read initial conditions and the written final conditions of sequence SM for the 12 hydrological response units of the subcatchment land_dill_assl:

>>> with TestIO():
...     filepath = "HydPy-H-Lahn/conditions/init_1996_01_01_00_00_00/land_dill_assl.py"
...     with open(filepath) as file_:
...         print("".join(file_.readlines()[10:12]))
...     filepath = "HydPy-H-Lahn/conditions/init_1996_01_06/land_dill_assl.py"
...     with open(filepath) as file_:
...         print("".join(file_.readlines()[12:14]))
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)

sm(184.555679, 180.625527, 199.183781, 195.950142, 212.04018, 209.48859,
   222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)

The intermediate soil moisture values have been stored in a NetCDF file called hland_96_state_sm.nc:

>>> import numpy
>>> from hydpy import print_vector
>>> from hydpy.core.netcdftools import netcdf4, chars2str, query_variable
>>> with TestIO():
...     ncfile = netcdf4.Dataset("HydPy-H-Lahn/series/soildata/hland_96_state_sm.nc")
...     chars2str(query_variable(ncfile, "station_id")[:].data)[:3]
...     print_vector(query_variable(ncfile, "hland_96_state_sm")[:, 0])
['land_dill_assl_0', 'land_dill_assl_1', 'land_dill_assl_2']
184.972725, 184.789363, 184.643666, 184.589448, 184.555679
>>> ncfile.close()

Spatially averaged time series values have been stored in files ending with the suffix _mean:

>>> import time
>>> time.sleep(10)
>>> with TestIO(clear_all=True):
...     print_vector(
...         numpy.load("HydPy-H-Lahn/series/averages/lahn_marb_sim_q_mean.npy")[13:]
...     )
9.646776, 8.512748, 7.777124, 7.343268, 7.156948

Module xmltools implements the following members:


hydpy.auxs.xmltools.find(root: Element, name: str, optional: Literal[True, False] = True) Element | None[source]

Return the first XML element with the given name found in the given XML root.

>>> from hydpy.auxs.xmltools import find, XMLInterface
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("single_run.xml", make_filepath("HydPy-H-Lahn"))
>>> find(interface.root, "timegrid").tag.endswith("timegrid")
True

By default, function find() returns None in case the required element is missing:

>>> find(interface.root, "wrong")

Set the argument optional to False to let function find() raise errors instead:

>>> find(interface.root, "wrong", optional=False)
Traceback (most recent call last):
...
AttributeError: The actual XML element `config` does not define a XML subelement named `wrong`.  Please make sure your XML file follows the relevant XML schema.
hydpy.auxs.xmltools.strip(name: str) str[source]

Remove the XML namespace from the given string and return it.

>>> from hydpy.auxs.xmltools import strip
>>> strip("{https://github.com/something.xsd}something")
'something'
class hydpy.auxs.xmltools.PrepareSeriesArguments(allocate_ram: bool, read_jit: bool, write_jit: bool)[source]

Bases: NamedTuple

Helper class that determines and provides the arguments for function prepare_series().

allocate_ram: bool

Alias for field number 0

read_jit: bool

Alias for field number 1

write_jit: bool

Alias for field number 2

classmethod from_xmldata(is_reader: bool, is_input: bool, prefer_ram: bool) PrepareSeriesArguments[source]

Create a PrepareSeriesArguments object based on the (already prepared) information of an XML file.

Meaning of the arguments:
  • is_reader: is the current XML-Element responsible for reading (or writing)?

  • is_input: serve the addressed sequences as inputs (or outputs)?

  • prefer_ram: prefer to handle time series data in RAM (or read and write it just in time)?

>>> from hydpy.auxs.xmltools import PrepareSeriesArguments
>>> from_xmldata = PrepareSeriesArguments.from_xmldata

Test cases for reading input data:

>>> from_xmldata(is_reader=True, is_input=True, prefer_ram=True)
PrepareSeriesArguments(allocate_ram=True, read_jit=False, write_jit=False)
>>> from_xmldata(is_reader=True, is_input=True, prefer_ram=False)
PrepareSeriesArguments(allocate_ram=False, read_jit=True, write_jit=False)

Attempting to read output data results in an AssertionError (disallowed by all available XML schema files):

>>> from_xmldata(is_reader=True, is_input=False, prefer_ram=True)
Traceback (most recent call last):
...
AssertionError: reading output values is disallowed
>>> from_xmldata(is_reader=True, is_input=False, prefer_ram=False)
Traceback (most recent call last):
...
AssertionError: reading output values is disallowed

Test cases for writing input data (this is for the rare case where an external tool like OpenDA provides or modifies the input data in RAM, and we want to write it to a file for documentation purposes):

>>> from_xmldata(is_reader=False, is_input=True, prefer_ram=True)
PrepareSeriesArguments(allocate_ram=True, read_jit=False, write_jit=False)
>>> from_xmldata(is_reader=False, is_input=True, prefer_ram=False)
PrepareSeriesArguments(allocate_ram=True, read_jit=False, write_jit=True)

Test cases for writing output data:

>>> from_xmldata(is_reader=False, is_input=False, prefer_ram=True)
PrepareSeriesArguments(allocate_ram=True, read_jit=False, write_jit=False)
>>> from_xmldata(is_reader=False, is_input=False, prefer_ram=False)
PrepareSeriesArguments(allocate_ram=False, read_jit=False, write_jit=True)
hydpy.auxs.xmltools.run_simulation(projectname: str, xmlfile: str) None[source]

Perform a HydPy workflow according to the given XML configuration file available in the given project’s directory.

Function run_simulation() is a “script function”. We explain its normal usage in the main documentation on module xmltools.

class hydpy.auxs.xmltools.XMLBase[source]

Bases: object

Base class for the concrete classes XMLInterface, XMLConditions, XMLSeries, and XMLSubseries.

Subclasses of XMLBase support iterating XML subelements while skipping those named selections:

>>> from hydpy.auxs.xmltools import XMLInterface
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("multiple_runs.xml", make_filepath("HydPy-H-Lahn"))
>>> itemgroup = interface.exchange.itemgroups[1]
>>> for element in itemgroup:
...     print(strip(element.tag))
hland_96
rconc_uh
>>> for element in itemgroup.models[0].subvars[0].vars[0]:
...     print(strip(element.tag))
name
level
root: Element
property name: str

Apply function strip() to the root of the object of the XMLBase subclass.

>>> from hydpy.auxs.xmltools import XMLInterface
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("single_run.xml", make_filepath("HydPy-H-Lahn"))
>>> interface.name
'config'
>>> interface.series_io.readers[0].name
'reader'
find(name: str, optional: Literal[True, False] = True) Element | None[source]

Apply function find() to the root of the object of the XMLBase subclass.

>>> from hydpy.auxs.xmltools import XMLInterface
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("single_run.xml", make_filepath("HydPy-H-Lahn"))
>>> interface.find("timegrid").tag.endswith("timegrid")
True
>>> interface.find("wrong")
>>> interface.find("wrong", optional=False)
Traceback (most recent call last):
...
AttributeError: The actual XML element `config` does not define a XML subelement named `wrong`.  Please make sure your XML file follows the relevant XML schema.
class hydpy.auxs.xmltools.XMLInterface(filename: str, directory: str | None = None)[source]

Bases: XMLBase

An interface to XML configuration files that are valid concerning schema file HydPyConfigSingleRun.xsd or HydPyConfigMultipleRuns.xsd.

>>> from hydpy.auxs.xmltools import XMLInterface
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("single_run.xml", make_filepath("HydPy-H-Lahn"))
>>> interface.root.tag
'{https://github.com/hydpy-dev/hydpy/releases/download/your-hydpy-version/HydPyConfigSingleRun.xsd}config'
>>> interface = XMLInterface('multiple_runs.xml', make_filepath('HydPy-H-Lahn'))
>>> interface.root.tag
'{https://github.com/hydpy-dev/hydpy/releases/download/your-hydpy-version/HydPyConfigMultipleRuns.xsd}config'
>>> XMLInterface('wrongfilepath.xml', 'wrongdir')  
Traceback (most recent call last):
...
FileNotFoundError: While trying to parse the XML configuration file ...wrongfilepath.xml, the following error occurred: [Errno 2] No such file or directory: '...wrongfilepath.xml'
validate_xml() None[source]

Raise an error if the actual XML does not agree with one of the available schema files.

# ToDo: should it be accompanied by a script function?

The first example relies on a distorted version of the configuration file single_run.xml:

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import TestIO, xml_replace
>>> from hydpy.auxs.xmltools import XMLInterface
>>> import os
>>> with TestIO():  
...     xml_replace("HydPy-H-Lahn/single_run",
...                 firstdate="1996-01-32T00:00:00")
template file: HydPy-H-Lahn/single_run.xmlt
target file: HydPy-H-Lahn/single_run.xml
replacements:
  config_start --> <...HydPyConfigBase.xsd"
              ...HydPyConfigSingleRun.xsd"> (default argument)
  firstdate --> 1996-01-32T00:00:00 (given argument)
  zip_ --> false (default argument)
  config_end --> </hpcsr:config> (default argument)
>>> with TestIO():
...     interface = XMLInterface("single_run.xml", "HydPy-H-Lahn")
>>> interface.validate_xml()  
Traceback (most recent call last):
...
xmlschema.validators.exceptions.XMLSchemaDecodeError: While trying to validate XML file `...single_run.xml`, the following error occurred: failed validating '1996-01-32T00:00:00' with XsdAtomicBuiltin(name='xs:dateTime')...
...
Reason: day is out of range for month
...
Schema component:
...
Instance:
...
  <firstdate xmlns="https://github.com/hydpy-dev/hydpy/releases/download/your-hydpy-version/HydPyConfigBase.xsd">1996-01-32T00:00:00</firstdate>
...
Path: /hpcsr:config/timegrid/firstdate
...

In the second example, we examine a correct configuration file:

>>> with TestIO():  
...     xml_replace("HydPy-H-Lahn/single_run")
...     interface = XMLInterface("single_run.xml", "HydPy-H-Lahn")
template file: HydPy-H-Lahn/single_run.xmlt
target file: HydPy-H-Lahn/single_run.xml
replacements:
  config_start --> <...HydPyConfigBase.xsd"
              ...HydPyConfigSingleRun.xsd"> (default argument)
  firstdate --> 1996-01-01T00:00:00 (default argument)
  zip_ --> false (default argument)
  config_end --> </hpcsr:config> (default argument)
>>> interface.validate_xml()

The XML configuration file must correctly refer to the corresponding schema file:

>>> with TestIO():
...     xml_replace("HydPy-H-Lahn/single_run",
...                 config_start="<config>",
...                 config_end="</config>")
...     interface = XMLInterface("single_run.xml", "HydPy-H-Lahn")
template file: HydPy-H-Lahn/single_run.xmlt
target file: HydPy-H-Lahn/single_run.xml
replacements:
  config_start --> <config> (given argument)
  firstdate --> 1996-01-01T00:00:00 (default argument)
  zip_ --> false (default argument)
  config_end --> </config> (given argument)
>>> interface.validate_xml()  
Traceback (most recent call last):
...
RuntimeError: While trying to validate XML file `...single_run.xml`, the following error occurred: Configuration file `single_run.xml` does not correctly refer to one of the available XML schema files (HydPyConfigSingleRun.xsd and HydPyConfigMultipleRuns.xsd).

XML files based on HydPyConfigMultipleRuns.xsd can be validated as well:

>>> with TestIO():
...     interface = XMLInterface("multiple_runs.xml", "HydPy-H-Lahn")
>>> interface.validate_xml()
update_options() None[source]

Update the Options object available in the pub module with the values defined in the options XML element.

>>> from hydpy.auxs.xmltools import XMLInterface
>>> from hydpy import pub
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("single_run.xml", make_filepath("HydPy-H-Lahn"))
>>> pub.options.ellipsis = 0
>>> pub.options.parameterstep = "1h"
>>> pub.options.printprogress = True
>>> pub.options.reprdigits = -1
>>> pub.options.utcoffset = -60
>>> pub.options.timestampleft = False
>>> pub.options.warnsimulationstep = 0
>>> interface.update_options()
>>> pub.options
Options(
    checkseries -> TRUE
    ellipsis -> 0
    parameterstep -> Period("1d")
    printprogress -> FALSE
    reprdigits -> 6
    simulationstep -> Period()
    timestampleft -> TRUE
    trimvariables -> TRUE
    usecython -> TRUE
    usedefaultvalues -> FALSE
    utclongitude -> 15
    utcoffset -> 60
    warnmissingcontrolfile -> FALSE
    warnmissingobsfile -> TRUE
    warnmissingsimfile -> TRUE
    warnsimulationstep -> FALSE
    warntrim -> TRUE
)
>>> pub.options.printprogress = False
>>> pub.options.reprdigits = 6
update_timegrids() None[source]

Update the Timegrids object available in the pub module with the values defined in the timegrid XML element.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, TestIO
>>> from hydpy.auxs.xmltools import XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> with TestIO():
...     XMLInterface("single_run.xml").update_timegrids()
>>> pub.timegrids
Timegrids("1996-01-01T00:00:00",
          "1996-01-06T00:00:00",
          "1d")
update_selections() None[source]

Create Selection objects based on the add_selections XML element and add them to the Selections object available in module pub.

The Lahn example project comes with four selections:

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, TestIO
>>> from hydpy.auxs.xmltools import find, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> with TestIO():
...     hp.prepare_network()
...     interface = XMLInterface("single_run.xml")
>>> pub.selections
Selections("complete", "headwaters", "nonheadwaters", "streams")

Following the definitions of the add_selections element of the configuration file single_run.xml, method update_selections() creates three additional selections based on given device names, keywords, or selection names (you could also combine these subelements):

>>> interface.update_selections()
>>> pub.selections
Selections("complete", "from_devices", "from_keywords",
           "from_selections", "headwaters", "nonheadwaters", "streams")
>>> pub.selections.from_devices
Selection("from_devices",
          nodes=(),
          elements=("land_lahn_leun", "land_lahn_marb"))
>>> pub.selections.from_keywords
Selection("from_keywords",
          nodes=(),
          elements=("land_dill_assl", "land_lahn_kalk",
                    "land_lahn_leun", "land_lahn_marb"))
>>> pub.selections.from_selections
Selection("from_selections",
          nodes=("dill_assl", "lahn_kalk", "lahn_leun", "lahn_marb"),
          elements=("land_dill_assl", "land_lahn_kalk",
                    "land_lahn_leun", "land_lahn_marb",
                    "stream_dill_assl_lahn_leun",
                    "stream_lahn_leun_lahn_kalk",
                    "stream_lahn_marb_lahn_leun"))

Defining wrong device names, keywords, or selection names results in error messages:

>>> add_selections = find(interface.root, "add_selections")
>>> add_selections[2][1].text = "streams no_selection"
>>> interface.update_selections()
Traceback (most recent call last):
...
RuntimeError: The XML configuration file tried to add the devices of a selection named `no_selection` to the custom selection `from_selections` but none of the available selections has this name.
>>> add_selections[1][1].text = "catchment no_keyword"
>>> interface.update_selections()
Traceback (most recent call last):
...
RuntimeError: The XML configuration file tried to add at least one device based on the keyword `no_keyword` to the custom selection `from_keywords` but none of the available devices has this keyword.
>>> add_selections[0][1].text = "dill_assl no_device"
>>> interface.update_selections()
Traceback (most recent call last):
...
RuntimeError: The XML configuration file tried to add a device named `no_device` to the custom selection `from_devices` but none of the available devices has this name.
property selections: Selections

The Selections object defined on the main level of the actual XML file.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> with TestIO():
...     hp.prepare_network()
...     interface = XMLInterface("single_run.xml")
>>> interface.update_selections()
>>> interface.find("selections").text = "headwaters streams"
>>> selections = interface.selections
>>> for selection in selections:
...     print(selection.name)
headwaters
streams
>>> selections.headwaters
Selection("headwaters",
          nodes=("dill_assl", "lahn_marb"),
          elements=("land_dill_assl", "land_lahn_marb"))
>>> interface.find("selections").text = "head_waters"
>>> interface.selections
Traceback (most recent call last):
...
NameError: The XML configuration file tries to define a selection using the text `head_waters`, but the actual project does not handle such a `Selection` object.
property elements: Iterator[Element]

Yield all Element objects returned by selections without duplicates.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> with TestIO():
...     hp.prepare_network()
...     interface = XMLInterface("single_run.xml")
>>> interface.update_timegrids()
>>> interface.update_selections()
>>> interface.find("selections").text = "headwaters streams"
>>> for element in interface.elements:
...      print(element.name)
land_dill_assl
land_lahn_marb
stream_dill_assl_lahn_leun
stream_lahn_leun_lahn_kalk
stream_lahn_marb_lahn_leun
property fullselection: Selection

A Selection object that contains all Element and Node objects defined by selections.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> with TestIO():
...     hp.prepare_network()
...     interface = XMLInterface("single_run.xml")
>>> interface.update_selections()
>>> interface.find("selections").text = "nonheadwaters"
>>> interface.fullselection
Selection("fullselection",
          nodes=("lahn_kalk", "lahn_leun"),
          elements=("land_lahn_kalk", "land_lahn_leun"))
>>> interface.find("selections").text = "from_keywords"
>>> interface.fullselection
Selection("fullselection",
          nodes=(),
          elements=("land_dill_assl", "land_lahn_kalk",
                    "land_lahn_leun", "land_lahn_marb"))
property network_io: XMLNetworkDefault | XMLNetworkUserDefined

The network_io element defined in the actual XML file.

>>> from hydpy.auxs.xmltools import XMLInterface, strip
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("single_run.xml", make_filepath("HydPy-H-Lahn"))
>>> interface.network_io.text
'default'
>>> interface = XMLInterface("multiple_runs.xml", make_filepath("HydPy-H-Lahn"))
>>> interface.network_io.text
'default'
property control_io: XMLControlDefault | XMLControlUserDefined

The control_io element defined in the actual XML file.

>>> from hydpy.auxs.xmltools import XMLInterface, strip
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("single_run.xml", make_filepath("HydPy-H-Lahn"))
>>> interface.control_io.text
'default'
>>> interface = XMLInterface("multiple_runs.xml", make_filepath("HydPy-H-Lahn"))
>>> interface.control_io.text
'default'
property conditions_io: XMLConditions

The condition_io element defined in the actual XML file.

>>> from hydpy.auxs.xmltools import XMLInterface, strip
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("single_run.xml", make_filepath("HydPy-H-Lahn"))
>>> strip(interface.series_io.root.tag)
'series_io'
property series_io: XMLSeries

The series_io element defined in the actual XML file.

>>> from hydpy.auxs.xmltools import XMLInterface, strip
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("single_run.xml", make_filepath("HydPy-H-Lahn"))
>>> strip(interface.series_io.root.tag)
'series_io'
property exchange: XMLExchange

The exchange element defined in the actual XML file.

>>> from hydpy.auxs.xmltools import XMLInterface, strip
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface(
...     "multiple_runs.xml", make_filepath("HydPy-H-Lahn"))
>>> strip(interface.exchange.root.tag)
'exchange'
class hydpy.auxs.xmltools.XMLNetworkBase[source]

Bases: object

Base class for XMLNetworkDefault and XMLNetworkUserDefined.

master: XMLInterface
text: str | None
prepare_network() None[source]

Prepare the Selections object available in the global pub module:

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import attrready, HydPy, pub, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     interface = XMLInterface("single_run.xml")
...     interface.find("network_io").text = "wrong"
...     interface.network_io.prepare_network()  
Traceback (most recent call last):
...
RuntimeError: The directory `...wrong` does not contain any network files.
>>> with TestIO():
...     interface = XMLInterface("single_run.xml")
...     interface.find("network_io").text = "default"
...     interface.network_io.prepare_network()  
>>> pub.selections
Selections("complete", "headwaters", "nonheadwaters", "streams")
class hydpy.auxs.xmltools.XMLNetworkDefault(master: XMLInterface, text: str | None)[source]

Bases: XMLNetworkBase

Helper class for XMLInterface responsible for loading devices from network files when the XML file does not specify a network directory.

class hydpy.auxs.xmltools.XMLNetworkUserDefined(master: XMLInterface, root: Element, text: str | None)[source]

Bases: XMLBase, XMLNetworkBase

Helper class for XMLInterface responsible for loading devices from network files when the XML file specifies a network directory.

class hydpy.auxs.xmltools.XMLControlBase[source]

Bases: object

Base class for XMLControlDefault and XMLControlUserDefined.

master: XMLInterface
text: str | None
prepare_models() None[source]

Prepare the Model objects of all Element objects returned by elements:

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import attrready, HydPy, pub, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_network()
...     interface = XMLInterface("single_run.xml")
...     interface.update_selections()
...     interface.find("selections").text = "headwaters"
...     interface.control_io.prepare_models()
>>> interface.update_timegrids()
>>> hp.elements.land_lahn_marb.model.parameters.control.alpha
alpha(1.0)
>>> attrready(hp.elements.land_lahn_leun, "model")
False
class hydpy.auxs.xmltools.XMLControlDefault(master: XMLInterface, text: str | None)[source]

Bases: XMLControlBase

Helper class for XMLInterface responsible for loading models from control files when the XML file does not specify a control directory.

class hydpy.auxs.xmltools.XMLControlUserDefined(master: XMLInterface, root: Element, text: str | None)[source]

Bases: XMLBase, XMLControlBase

Helper class for XMLInterface responsible for loading models from control files when the XML file specifies a control directory.

class hydpy.auxs.xmltools.XMLConditions(master: XMLInterface, root: Element)[source]

Bases: XMLBase

Helper class for XMLInterface responsible for loading and saving initial conditions.

load_conditions(currentdir: str | None = None) None[source]

Load the condition files of the Model objects of all Element objects returned by elements:

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_network()
...     hp.prepare_models()
...     interface = XMLInterface("single_run.xml")
...     interface.update_selections()
...     interface.find("selections").text = "headwaters"
...     interface.conditions_io.load_conditions()
>>> interface.update_timegrids()
>>> hp.elements.land_lahn_marb.model.sequences.states.lz
lz(8.18711)
>>> hp.elements.land_lahn_leun.model.sequences.states.lz
lz(nan)
save_conditions(currentdir: str | None = None) None[source]

Save the condition files of the Model objects of all Element objects returned by elements:

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> import os
>>> from hydpy import HydPy, pub, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_network()
...     hp.prepare_models()
...     hp.elements.land_dill_assl.model.sequences.states.lz = 999.0
...     interface = XMLInterface("single_run.xml")
...     interface.update_timegrids()
...     interface.update_selections()
...     interface.find("selections").text = "headwaters"
...     interface.conditions_io.save_conditions()
...     dirpath = "HydPy-H-Lahn/conditions/init_1996_01_06"
...     with open(os.path.join(dirpath, "land_dill_assl.py")) as file_:
...         print(file_.readlines()[12].strip())
...     os.path.exists(os.path.join(dirpath, "land_lahn_leun.py"))
lz(999.0)
False
>>> from hydpy import xml_replace
>>> with TestIO():
...     xml_replace("HydPy-H-Lahn/single_run", printflag=False, zip_="true")
...     interface = XMLInterface("single_run.xml")
...     interface.find("selections").text = "headwaters"
...     os.path.exists("HydPy-H-Lahn/conditions/init_1996_01_06.zip")
...     interface.conditions_io.save_conditions()
...     os.path.exists("HydPy-H-Lahn/conditions/init_1996_01_06.zip")
False
True
class hydpy.auxs.xmltools.XMLSeries(master: XMLInterface, root: Element)[source]

Bases: XMLBase

Helper class for XMLInterface responsible for loading and saving time series data, which is further delegated to suitable instances of class XMLSubseries.

property readers: list[XMLSubseries]

The reader XML elements defined in the actual XML file.

>>> from hydpy.auxs.xmltools import XMLInterface
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("single_run.xml", make_filepath("HydPy-H-Lahn"))
>>> for reader in interface.series_io.readers:
...     print(reader.info)
all input data
property writers: list[XMLSubseries]

The writer XML elements defined in the actual XML file.

>>> from hydpy.auxs.xmltools import XMLInterface
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("single_run.xml", make_filepath("HydPy-H-Lahn"))
>>> for writer in interface.series_io.writers:
...     print(writer.info)
precipitation
soilmoisture
averaged
prepare_series() None[source]

Call prepare_series() of all XMLSubseries objects.

load_series(currentdir: str | None = None) None[source]

Call load_series() of all XMLSubseries objects handled as “readers”.

save_series(currentdir: str | None = None) None[source]

Call load_series() of all XMLSubseries objects handled as “writers”.

modify_inputdir(currentdir: str | None = None) Iterator[None][source]

Temporarily modify the dirpath of all IOSequence objects registered for reading time series data “just in time” during a simulation run.

modify_outputdir(currentdir: str | None = None) Iterator[None][source]

Temporarily modify the dirpath of all IOSequence objects registered for writing time series data “just in time” during a simulation run.

class hydpy.auxs.xmltools.XMLSelector[source]

Bases: XMLBase

Base class for XMLSubseries and XMLVar responsible for querying the relevant Node and Element objects.

master: XMLBase
root: Element
property selections: Selections

The Selections object defined for the respective respective IO series or exchange item elements of the actual XML file.

Property selections of class XMLSelector falls back to the general property selections of XMLInterface if the relevant IO series or exchange item element does not define a unique selection:

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_network()
...     hp.prepare_models()
...     interface = XMLInterface("single_run.xml")
>>> interface.update_selections()
>>> series_io = interface.series_io
>>> for seq in (series_io.readers + series_io.writers):
...     print(seq.info, seq.selections.names)
all input data ('from_keywords',)
precipitation ('headwaters', 'from_devices')
soilmoisture ('complete',)
averaged ('from_selections',)

If property selections does not find any definitions, it raises the following error:

>>> interface.root.remove(interface.find("selections"))
>>> series_io = interface.series_io
>>> for seq in (series_io.readers + series_io.writers):
...     print(seq.info, seq.selections.names)
Traceback (most recent call last):
...
AttributeError: Unable to find a XML element named "selections".  Please make sure your XML file follows the relevant XML schema.
property elements: Iterator[Element]

Return the Element objects selected by the actual IO series or exchange item element.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> with TestIO():
...     hp.prepare_network()
...     interface = XMLInterface("single_run.xml")
>>> interface.update_selections()
>>> for element in interface.series_io.writers[0].elements:
...     print(element.name)
land_dill_assl
land_lahn_marb
land_lahn_leun
property nodes: Iterator[Node]

Return the Node objects selected by the actual IO series or exchange item element.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> with TestIO():
...     hp.prepare_network()
...     interface = XMLInterface("single_run.xml")
>>> interface.update_selections()
>>> for node in interface.series_io.writers[0].nodes:
...     print(node.name)
dill_assl
lahn_marb
class hydpy.auxs.xmltools.XMLSubseries(master: XMLSeries, root: Element)[source]

Bases: XMLSelector

Helper class for XMLSeries responsible for loading and saving time series data.

property info: str

Info attribute of the actual XML reader or writer element.

prepare_sequencemanager(currentdir: str | None = None) None[source]

Configure the SequenceManager object available in module pub following the definitions of the actual XML reader or writer element when available; if not, use those of the XML series_io element or fall back to the default.

Compare the following results with single_run.xml to see that the first writer element re-defines the default file type (asc), that the second writer element defines an alternative file type (npy), and that the third writer relies on the general file type. The base mechanism is the same for other options, e.g. the aggregation mode.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, TestIO, XMLInterface, pub
>>> hp = HydPy("HydPy-H-Lahn")
>>> with TestIO():
...     hp.prepare_network()
...     interface = XMLInterface("single_run.xml")
>>> series_io = interface.series_io
>>> with TestIO():
...     series_io.writers[0].prepare_sequencemanager()
...     pub.sequencemanager.currentdir
'default'
>>> pub.sequencemanager.filetype
'asc'
>>> pub.sequencemanager.overwrite
TRUE
>>> pub.sequencemanager.aggregation
'none'
>>> pub.sequencemanager.convention
'model-specific'
>>> with TestIO():
...     series_io.writers[1].prepare_sequencemanager()
...     pub.sequencemanager.currentdir
'soildata'
>>> pub.sequencemanager.filetype
'nc'
>>> pub.sequencemanager.overwrite
FALSE
>>> pub.sequencemanager.aggregation
'none'
>>> pub.sequencemanager.convention
'model-specific'
>>> with TestIO():
...     series_io.writers[2].prepare_sequencemanager()
...     pub.sequencemanager.currentdir
'averages'
>>> pub.sequencemanager.filetype
'npy'
>>> pub.sequencemanager.aggregation
'mean'
>>> pub.sequencemanager.overwrite
TRUE
>>> pub.sequencemanager.aggregation
'mean'
>>> pub.sequencemanager.convention
'model-specific'
property model2subs2seqs: defaultdict[str, defaultdict[str, list[str]]]

A nested defaultdict containing the model-specific information provided by the XML sequences element.

>>> from hydpy.auxs.xmltools import XMLInterface
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("single_run.xml", make_filepath("HydPy-H-Lahn"))
>>> series_io = interface.series_io
>>> model2subs2seqs = series_io.writers[2].model2subs2seqs
>>> for model, subs2seqs in sorted(model2subs2seqs.items()):
...     for subs, seq in sorted(subs2seqs.items()):
...         print(model, subs, seq)
hland_96 factors ['tc']
hland_96 fluxes ['tf']
hland_96 states ['sm']
musk_classic states ['discharge']
property subs2seqs: dict[str, list[str]]

A defaultdict containing the node-specific information provided by XML sequences element.

>>> from hydpy.auxs.xmltools import XMLInterface
>>> from hydpy.data import make_filepath
>>> interface = XMLInterface("single_run.xml", make_filepath("HydPy-H-Lahn"))
>>> series_io = interface.series_io
>>> subs2seqs = series_io.writers[2].subs2seqs
>>> for subs, seq in sorted(subs2seqs.items()):
...     print(subs, seq)
node ['sim', 'obs']
prepare_series() None[source]

Call method prepare_series() of class IOSequence for all sequences selected by the given element of the actual XML file.

Method prepare_series() solves a complex task, as it needs to determine the correct arguments for method prepare_series() of class IOSequence. Those arguments depend on whether the respective XMLSubseries element is for reading or writing data, addresses input or output sequences, and if one prefers to handle time series data in RAM or read or write it “just in time” during model simulations. Method prepare_series() delegates some of the related logic to the from_xmldata() method of class PrepareSeriesArguments. The following examples demonstrate that method prepare_series() implements the remaining logic correctly.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_network()
...     hp.prepare_models()
...     interface = XMLInterface("single_run.xml")
>>> interface.update_timegrids()
>>> interface.update_selections()

First, we check and discuss the proper setting of the properties ramflag, diskflag_reading, and diskflag_writing for the sequences defined in single_run.xml. First, we call prepare_series() for available XMLSubseries objects:

>>> series_io = interface.series_io
>>> for reader in series_io.readers:
...     reader.prepare_series()
>>> for writer in series_io.writers:
...     writer.prepare_series()

The following test function prints the options of the specified sequence of element “Dill_assl”:

>>> def print_io_options(groupname, sequencename):
...     sequences = hp.elements.land_dill_assl.model.sequences
...     sequence = sequences[groupname][sequencename]
...     print(f"ramflag={sequence.ramflag}")
...     print(f"diskflag_reading={sequence.diskflag_reading}")
...     print(f"diskflag_writing={sequence.diskflag_writing}")

The XML file uses the jit mode for all non-aggregated time series. Reader elements handle input sequences and writer elements handle output sequences. Hence, ramflag is generally False while diskflag_reading is True for the input sequences and diskflag_writing is True for the output sequences:

>>> print_io_options("inputs", "p")
ramflag=False
diskflag_reading=True
diskflag_writing=False
>>> print_io_options("fluxes", "pc")
ramflag=False
diskflag_reading=False
diskflag_writing=True

Currently, aggregation only works in combination with mode ram:

>>> print_io_options("factors", "tc")
ramflag=True
diskflag_reading=False
diskflag_writing=False

For sequence SM, two writers apply. The writer “soil moisture” triggers writing the complete time series “just in time” during the simulation run. In contrast, the writer “averaged” initiates writing averaged time series after the simulation run. The configuration of sequence SM reflects this, with both “ram flag” and “disk flag writing” being “True”:

>>> print_io_options("states", "sm")
ramflag=True
diskflag_reading=False
diskflag_writing=True

We temporarily convert the single reader element to a writer element and apply method prepare_series() again. At first, this does not work, as the affected input sequences have previously been configured for “just in time” reading, which does not work in combination with “just in time” writing:

>>> reader = series_io.readers[0]
>>> reader.root.tag = reader.root.tag.replace("reader", "writer")
>>> reader.prepare_series()
Traceback (most recent call last):
...
ValueError: Reading from and writing into the same NetCDF file "just in time" during a simulation run is not supported but tried for sequence `p` of element `land_dill_assl`.

After resetting all InputSequence objects and re-applying prepare_series(), both ramflag and diskflag_writing are True. This case is the only one where a single reader or writer enables two flags (see the documentation on method from_xmldata() for further information):

>>> hp.prepare_allseries(allocate_ram=False, jit=False)
>>> reader.prepare_series()
>>> reader.root.tag = reader.root.tag.replace("writer", "reader")
>>> print_io_options("inputs", "p")
ramflag=True
diskflag_reading=False
diskflag_writing=True

If we prefer the ram mode, things are more straightforward. Then, option ramflag is True, and options diskflag_reading and diskflag_writing are False regardless of all other options:

>>> hp.prepare_allseries(allocate_ram=False, jit=False)
>>> series_io.find("mode").text = "ram"
>>> for reader in series_io.readers:
...     reader.find("mode").text = "ram"
...     reader.prepare_series()
>>> for writer in series_io.writers:
...     mode = writer.find("mode")
...     if mode is not None:
...         mode.text = "ram"
...     writer.prepare_series()
>>> print_io_options("inputs", "p")
ramflag=True
diskflag_reading=False
diskflag_writing=False
>>> print_io_options("fluxes", "pc")
ramflag=True
diskflag_reading=False
diskflag_writing=False
>>> print_io_options("states", "sm")
ramflag=True
diskflag_reading=False
diskflag_writing=False
>>> reader = series_io.readers[0]
>>> reader.root.tag = reader.root.tag.replace("reader", "writer")
>>> reader.prepare_series()
>>> reader.root.tag = reader.root.tag.replace("writer", "reader")
>>> print_io_options("inputs", "p")
ramflag=True
diskflag_reading=False
diskflag_writing=False
load_series(currentdir: str | None) None[source]

Load time series data as defined by the actual XML reader element.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, TestIO, xml_replace, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_network()
...     hp.prepare_models()
...     xml_replace("HydPy-H-Lahn/single_run", printflag=False)
...     interface = XMLInterface("single_run.xml")
...     interface.update_options()
...     interface.update_timegrids()
...     interface.update_selections()
...     series_io = interface.series_io
...     series_io.prepare_series()
...     series_io.load_series()
>>> from hydpy import print_vector
>>> print_vector(hp.elements.land_dill_assl.model.sequences.inputs.t.series[:3])
0.0, -0.5, -2.4
save_series(currentdir: str | None) None[source]

Save time series data as defined by the actual XML writer element.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, round_, TestIO, xml_replace, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_network()
...     hp.prepare_models()
...     xml_replace("HydPy-H-Lahn/single_run", printflag=False)
...     interface = XMLInterface("single_run.xml")
>>> interface.update_options()
>>> interface.update_timegrids()
>>> interface.update_selections()
>>> series_io = interface.series_io
>>> series_io.prepare_series()
>>> hp.elements.land_dill_assl.model.sequences.fluxes.pc.series[2, 3] = 9.0
>>> hp.nodes.lahn_leun.sequences.sim.series[4] = 7.0
>>> with TestIO():
...     series_io.save_series()
>>> import numpy
>>> with TestIO():
...     dirpath = "HydPy-H-Lahn/series/default/"
...     os.path.exists(f"{dirpath}land_lahn_leun_hland_96_flux_pc.npy")
...     os.path.exists(f"{dirpath}land_lahn_kalk_hland_96_flux_pc.npy")
...     round_(numpy.load(f"{dirpath}land_dill_assl_hland_96"
...                       f"_flux_pc.npy")[13+2, 3])
...     round_(numpy.load(f"{dirpath}lahn_leun_sim_q_mean.npy")[13+4])
True
False
9.0
7.0
change_dirpath(currentdir: str | None) None[source]

Set the dirpath of all relevant IOSequence objects to the currentpath of the SequenceManager object available in the pub module.

This “information freezing” is required for those sequences selected for reading data from or writing data to different directories “just in time” during a simulation run.

reset_dirpath() None[source]

Revert change_dirpath().

class hydpy.auxs.xmltools.XMLExchange(master: XMLInterface, root: Element)[source]

Bases: XMLBase

Helper class for XMLInterface responsible for interpreting exchange items, accessible via different XMLItemgroup instances.

property parameteritems: list[ChangeItem]

Create and return all items for changing control parameter values.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_everything()
...     interface = XMLInterface("multiple_runs.xml")
>>> interface.update_selections()
>>> for item in interface.exchange.parameteritems:
...     print(item.name)
alpha
beta
lag
damp
sfcf_1
sfcf_2
sfcf_3
k4
property inputitems: list[SetItem]

Return all items for changing input sequence values.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_everything()
...     interface = XMLInterface("multiple_runs.xml")
>>> interface.update_selections()
>>> for item in interface.exchange.inputitems:
...     print(item.name)
t_headwaters
property conditionitems: list[SetItem]

Return all items for changing condition sequence values.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_everything()
...     interface = XMLInterface("multiple_runs.xml")
>>> interface.update_selections()
>>> for item in interface.exchange.conditionitems:
...     print(item.name)
ic_lahn_leun
ic_lahn_marb
sm_lahn_leun
sm_lahn_marb
quh
property outputitems: list[SetItem]

Return all items for querying the current values or the complete time series of sequences in the “setitem” style.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_everything()
...     interface = XMLInterface("multiple_runs.xml")
>>> interface.update_selections()
>>> for item in interface.exchange.outputitems:
...     print(item.name)
swe_headwaters
property getitems: list[GetItem]

Return all items for querying the current values or the complete time series of sequences in the “getitem style”.

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import HydPy, pub, TestIO, XMLInterface
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_everything()
...     interface = XMLInterface("multiple_runs.xml")
>>> interface.update_selections()
>>> for item in interface.exchange.getitems:
...     print(item.target)
factors_contriarea
fluxes_qt
fluxes_qt_series
states_sm
states_sm_series
nodes_sim_series
prepare_series() None[source]

Prepare all required series arrays via the prepare_series() method.

property itemgroups: list[XMLItemgroup]

The relevant XMLItemgroup objects.

class hydpy.auxs.xmltools.XMLItemgroup(master: XMLExchange, root: Element)[source]

Bases: XMLBase

Helper class for XMLExchange responsible for handling the exchange items related to model parameters and sequences separately from the exchange items of node sequences.

property models: list[XMLModel]

The required XMLModel objects.

property nodes: list[XMLNode]

The required XMLNode objects.

class hydpy.auxs.xmltools.XMLModel(master: XMLItemgroup, root: Element)[source]

Bases: XMLBase

Helper class for XMLItemgroup responsible for handling the exchange items related to different parameter or sequence groups of Model objects.

class hydpy.auxs.xmltools.XMLSubvars(master: XMLModel, root: Element)[source]

Bases: XMLBase

Helper class for XMLModel responsible for handling the exchange items related to individual parameters or sequences of Model objects.

property vars: list[XMLVar]

The required XMLVar objects.

class hydpy.auxs.xmltools.XMLNode(master: XMLItemgroup, root: Element)[source]

Bases: XMLBase

Helper class for XMLItemgroup responsible for handling the exchange items related to individual parameters or sequences of Node objects.

property vars: list[XMLVar]

The required XMLVar objects.

class hydpy.auxs.xmltools.XMLVar(master: XMLSubvars | XMLNode, root: Element)[source]

Bases: XMLSelector

Helper class for XMLSubvars and XMLNode responsible for creating a defined exchange item.

property item: ExchangeItem

The defined ExchangeItem object.

We first prepare the HydPy-H-Lahn example project and then create the related XMLInterface object defined by the XML configuration file multiple_runs:

>>> from hydpy.core.testtools import prepare_full_example_1
>>> prepare_full_example_1()
>>> from hydpy import (HydPy, round_, print_matrix, print_vector, pub, TestIO,
...                    XMLInterface)
>>> hp = HydPy("HydPy-H-Lahn")
>>> pub.timegrids = "1996-01-01", "1996-01-06", "1d"
>>> with TestIO():
...     hp.prepare_everything()
...     interface = XMLInterface("multiple_runs.xml")
>>> interface.update_selections()

One of the defined SetItem objects modifies the values of all Alpha objects of application model hland_96. We demonstrate this for the control parameter object handled by the land_dill_assl element:

>>> var = interface.exchange.itemgroups[0].models[0].subvars[0].vars[0]
>>> item = var.item
>>> round_(item.value)
2.0
>>> hp.elements.land_dill_assl.model.parameters.control.alpha
alpha(1.0)
>>> item.update_variables()
>>> hp.elements.land_dill_assl.model.parameters.control.alpha
alpha(2.0)

The second example is comparable but focuses on a SetItem modifying control parameter NmbSegments of application model musk_classic via its keyword argument lag:

>>> var = interface.exchange.itemgroups[0].models[2].subvars[0].vars[0]
>>> item = var.item
>>> round_(item.value)
5.0
>>> hp.elements.stream_dill_assl_lahn_leun.model.parameters.control.nmbsegments
nmbsegments(lag=0.0)
>>> item.update_variables()
>>> hp.elements.stream_dill_assl_lahn_leun.model.parameters.control.nmbsegments
nmbsegments(lag=5.0)

The third discussed SetItem assigns the same value to all entries of state sequence SM, resulting in the same soil moisture for all individual hydrological response units of element land_lahn_leun:

>>> var = interface.exchange.itemgroups[1].models[0].subvars[0].vars[2]
>>> item = var.item
>>> item.name
'sm_lahn_leun'
>>> print_vector(item.value)
123.0
>>> hp.elements.land_lahn_leun.model.sequences.states.sm
sm(138.31396, 135.71124, 147.54968, 145.47142, 154.96405, 153.32805,
   160.91917, 159.62434, 165.65575, 164.63255)
>>> item.update_variables()
>>> hp.elements.land_lahn_leun.model.sequences.states.sm
sm(123.0, 123.0, 123.0, 123.0, 123.0, 123.0, 123.0, 123.0, 123.0, 123.0)

In contrast to the last example, the fourth SetItem is 1-dimensional and thus allows to assign different values to the individual hydrological response units of element land_lahn_marb:

>>> var = interface.exchange.itemgroups[1].models[0].subvars[0].vars[3]
>>> item = var.item
>>> item.name
'sm_lahn_marb'
>>> print_vector(item.value)
110.0, 120.0, 130.0, 140.0, 150.0, 160.0, 170.0, 180.0, 190.0, 200.0,
210.0, 220.0, 230.0
>>> hp.elements.land_lahn_marb.model.sequences.states.sm
sm(99.27505, 96.17726, 109.16576, 106.39745, 117.97304, 115.56252,
   125.81523, 123.73198, 132.80035, 130.91684, 138.95523, 137.25983,
   142.84148)
>>> with pub.options.warntrim(False):
...     item.update_variables()
>>> hp.elements.land_lahn_marb.model.sequences.states.sm
sm(110.0, 120.0, 130.0, 140.0, 150.0, 160.0, 170.0, 180.0, 190.0, 200.0,
   206.0, 206.0, 206.0)

Without defining initial values in the XML file, the value property of each SetItem starts with the averaged (see item ic_lahn_leun) or original (see item ic_lahn_marb) values of the corresponding sequences:

>>> var = interface.exchange.itemgroups[1].models[0].subvars[0].vars[0]
>>> item = var.item
>>> item.name
'ic_lahn_leun'
>>> round_(item.value)
1.184948
>>> ic_states = hp.elements.land_lahn_leun.model.sequences.states.ic
>>> round_(ic_states.average_values())
1.184948
>>> var = interface.exchange.itemgroups[1].models[0].subvars[0].vars[1]
>>> item = var.item
>>> item.name
'ic_lahn_marb'
>>> print_vector(item.value)
0.96404, 1.36332, 0.96458, 1.46458, 0.96512, 1.46512, 0.96565,
1.46569, 0.96617, 1.46617, 0.96668, 1.46668, 1.46719
>>> hp.elements.land_lahn_marb.model.sequences.states.ic
ic(0.96404, 1.36332, 0.96458, 1.46458, 0.96512, 1.46512, 0.96565,
   1.46569, 0.96617, 1.46617, 0.96668, 1.46668, 1.46719)

Finally, one SetItem addresses the time series if the input sequence T of both headwater catchments. Similar to the example above, its initial values stem from its target sequences’ initial (time series) values:

>>> var = interface.exchange.itemgroups[2].models[0].subvars[0].vars[0]
>>> item = var.item
>>> print_matrix(item.value)
| 0.0, -0.5, -2.4, -6.8, -7.8 |
| -0.7, -1.5, -4.6, -8.2, -8.7 |
>>> print_vector(hp.elements.land_dill_assl.model.sequences.inputs.t.series)
0.0, -0.5, -2.4, -6.8, -7.8
>>> print_vector(hp.elements.land_lahn_marb.model.sequences.inputs.t.series)
-0.7, -1.5, -4.6, -8.2, -8.7
>>> item.value = [0.0, 1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0, 9.0]
>>> item.update_variables()
>>> print_vector(hp.elements.land_dill_assl.model.sequences.inputs.t.series)
0.0, 1.0, 2.0, 3.0, 4.0
>>> print_vector(hp.elements.land_lahn_marb.model.sequences.inputs.t.series)
5.0, 6.0, 7.0, 8.0, 9.0

AddItem sfcf_1, sfcf_2, and sfcf_3 serve to demonstrate how a scalar value (sfcf_1 and sfcf_2) or a vector of values can be used to change the value of a “target” parameter (SfCF) in relation to a “base” parameter (RfCF):

>>> for element in pub.selections.headwaters.elements:
...     element.model.parameters.control.rfcf(1.1)
>>> for element in pub.selections.nonheadwaters.elements:
...     element.model.parameters.control.rfcf(1.0)
>>> for subvars in interface.exchange.itemgroups[3].models[0].subvars:
...     for var in subvars.vars:
...         var.item.update_variables()
>>> for element in hp.elements.catchment:
...     print(element, repr(element.model.parameters.control.sfcf))
land_dill_assl sfcf(1.4)
land_lahn_kalk sfcf(field=1.1, forest=1.2)
land_lahn_leun sfcf(1.2)
land_lahn_marb sfcf(1.4)

MultiplyItem k4 works similar to the described add items but multiplies the current values of the base parameter objects of type K with 10 to gain new values for the target parameter objects of type K4:

>>> for subvars in interface.exchange.itemgroups[4].models[0].subvars:
...     for var in subvars.vars:
...         var.item.update_variables()
>>> for element in hp.elements.catchment:
...     control = element.model.parameters.control
...     print(element, repr(control.k), repr(control.k4))
land_dill_assl k(0.005618) k4(0.056177)
land_lahn_kalk k(0.002571) k4(0.025712)
land_lahn_leun k(0.005948) k4(0.059481)
land_lahn_marb k(0.005325) k4(0.053247)

The final three examples focus on GetItem objects. One GetItem object queries the actual values of the SM states of all relevant elements:

>>> var = interface.exchange.itemgroups[5].models[0].subvars[2].vars[0]
>>> hp.elements.land_dill_assl.model.sequences.states.sm = 1.0
>>> for name, target in var.item.yield_name2value():
...     print(name, target)  
land_dill_assl_states_sm [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
land_lahn_kalk_states_sm [101.3124...]
land_lahn_leun_states_sm [123.0, 123.0, 123.0, 123.0, 123.0, 123.0, 123.0, 123.0, 123.0, 123.0]
land_lahn_marb_states_sm [110.0, 120.0, 130.0, 140.0, 150.0, 160.0, 170.0, 180.0, 190.0, 200.0, 206.0, 206.0, 206.0]

Another GetItem object queries the actual value of the ContriArea factor sequence of element land_dill_assl:

>>> hp.elements.land_dill_assl.model.sequences.factors.contriarea(1.0)
>>> for var in interface.exchange.itemgroups[5].models[0].subvars[0].vars:
...     for name, target in var.item.yield_name2value():
...         print(name, target)
land_dill_assl_factors_contriarea 1.0

Another GetItem object queries both the actual and the time series values of the QT flux sequence of element land_dill_assl:

>>> qt = hp.elements.land_dill_assl.model.sequences.fluxes.qt
>>> qt(1.0)
>>> qt.series = 2.0
>>> for var in interface.exchange.itemgroups[5].models[0].subvars[1].vars:
...     for name, target in var.item.yield_name2value():
...         print(name, target)
land_dill_assl_fluxes_qt 1.0
land_dill_assl_fluxes_qt_series [2.0, 2.0, 2.0, 2.0, 2.0]

Last but not least, one GetItem queries the simulated time series values available through node dill_assl:

>>> var = interface.exchange.itemgroups[5].nodes[0].vars[0]
>>> hp.nodes.dill_assl.sequences.sim.series = range(5)
>>> for name, target in var.item.yield_name2value():
...     print(name, target)
dill_assl_nodes_sim_series [0.0, 1.0, 2.0, 3.0, 4.0]
>>> for name, target in var.item.yield_name2value(2, 4):
...     print(name, target)
dill_assl_nodes_sim_series [2.0, 3.0]
class hydpy.auxs.xmltools.XSDWriter[source]

Bases: object

A pure classmethod class for writing the actual XML schema file HydPyConfigBase.xsd, which makes sure that an XML configuration file is readable by class XMLInterface.

Unless you are interested in enhancing HydPy’s XML functionalities, you should, if any, be interested in method write_xsd() only.

confpath: str = '/home/travis/build/hydpy-dev/hydpy/.nox/sphinx/lib/python3.12/site-packages/hydpy/conf'
filepath_source: str = '/home/travis/build/hydpy-dev/hydpy/.nox/sphinx/lib/python3.12/site-packages/hydpy/conf/HydPyConfigBase.xsdt'
filepath_target: str = '/home/travis/build/hydpy-dev/hydpy/.nox/sphinx/lib/python3.12/site-packages/hydpy/conf/HydPyConfigBase.xsd'
classmethod write_xsd() None[source]

Write the complete base schema file HydPyConfigBase.xsd based on the template file HydPyConfigBase.xsdt.

Method write_xsd() adds model-specific information to the general information of template file HydPyConfigBase.xsdt regarding reading and writing of time series data and exchanging parameter and sequence values, for example, during calibration.

The following example shows that after writing a new schema file, method validate_xml() does not raise an error when either applied to the XML configuration files single_run.xml or multiple_runs.xml of the HydPy-H-Lahn example project:

>>> import os
>>> from hydpy.auxs.xmltools import XSDWriter, XMLInterface
>>> if os.path.exists(XSDWriter.filepath_target):
...     os.remove(XSDWriter.filepath_target)
>>> os.path.exists(XSDWriter.filepath_target)
False
>>> XSDWriter.write_xsd()
>>> os.path.exists(XSDWriter.filepath_target)
True
>>> from hydpy.data import make_filepath
>>> for configfile in ("single_run.xml", "multiple_runs.xml"):
...     XMLInterface(configfile, make_filepath("HydPy-H-Lahn")).validate_xml()
static get_basemodelnames() list[str][source]

Return a sorted list containing all base model names.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> print(XSDWriter.get_basemodelnames())  
['arma', 'conv', ..., 'wland', 'wq']
static get_applicationmodelnames() list[str][source]

Return a sorted list containing all application model names.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> print(XSDWriter.get_applicationmodelnames())  
[...'dam_v001', 'dam_v002', 'dam_v003', 'dam_v004', 'dam_v005',...]
classmethod get_insertion() str[source]

Return the complete string to be inserted into the string of the template file.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> print(XSDWriter.get_insertion())  
    <complexType name="dummy_interceptedwater_readerType">
        <sequence>
            <element name="inputs"
                     minOccurs="0">
                <complexType>
                    <sequence>
                        <element
                            name="interceptedwater"
                            minOccurs="0"/>
                    </sequence>
                </complexType>
            </element>
        </sequence>
    </complexType>
...
    <complexType name="dummy_snowalbedo_readerType">
        <sequence>
            <element name="inputs"
                     minOccurs="0">
                <complexType>
                    <sequence>
                        <element
                            name="snowalbedo"
                            minOccurs="0"/>
...
            <element name="wland_wag"
                     type="hpcb:wland_wag_readerType"
                     minOccurs="0"/>
        </sequence>
    </complexType>
...
    <complexType name="arma_rimorido_writerType">
        <sequence>
            <element name="fluxes"
                     minOccurs="0">
                <complexType>
                    <sequence>
                        <element
                            name="qin"
...
                        <element
                            name="qout"
                            minOccurs="0"/>
                    </sequence>
                </complexType>
            </element>
        </sequence>
    </complexType>
...
    <complexType name="writerType">
        <sequence>
            <element name="node"
                     type="hpcb:node_writerType"
                     minOccurs="0"/>
            <element name="arma_rimorido"
                     type="hpcb:arma_rimorido_writerType"
                     minOccurs="0"/>
...
            <element name="wq_trapeze_strickler"
                     type="hpcb:wq_trapeze_strickler_writerType"
                     minOccurs="0"/>
        </sequence>
    </complexType>
classmethod get_modelinsertion(model: modeltools.Model, type_: str, indent: int) str | None[source]

Return the insertion string required for the given application model.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> from hydpy import prepare_model
>>> model = prepare_model("hland_96")
>>> print(XSDWriter.get_modelinsertion(
...     model=model, type_="reader", indent=1))  
    <element name="inputs"
             minOccurs="0">
        <complexType>
            <sequence>
                <element
                    name="p"
                    minOccurs="0"/>
                <element
                    name="t"
                    minOccurs="0"/>
            </sequence>
        </complexType>
    </element>
>>> print(XSDWriter.get_modelinsertion(
...     model=model, type_="writer", indent=1))  
    <element name="inputs"
             minOccurs="0">
        <complexType>
            <sequence>
                <element
                    name="p"
                    minOccurs="0"/>
...
    </element>
    <element name="fluxes"
             minOccurs="0">
...
    </element>
    <element name="states"
             minOccurs="0">
...
    </element>
>>> model = prepare_model("arma_rimorido")
>>> XSDWriter.get_modelinsertion(
...     model=model, type_="reader", indent=1)  
>>> print(XSDWriter.get_modelinsertion(
...     model=model, type_="writer", indent=1))  
    <element name="fluxes"
             minOccurs="0">
        <complexType>
            <sequence>
                <element
                    name="qin"
                    minOccurs="0"/>
    ...
                <element
                    name="qout"
                    minOccurs="0"/>
            </sequence>
        </complexType>
    </element>
classmethod get_subsequencesinsertion(subsequences: SubSequences[Any, Any, Any], indent: int) str[source]

Return the insertion string required for the given group of sequences.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> from hydpy import prepare_model
>>> model = prepare_model("hland_96")
>>> print(XSDWriter.get_subsequencesinsertion(
...     model.sequences.factors, 1))  
    <element name="factors"
             minOccurs="0">
        <complexType>
            <sequence>
                <element
                    name="tc"
                    minOccurs="0"/>
                <element
                    name="fracrain"
                    minOccurs="0"/>
...
                <element
                    name="contriarea"
                    minOccurs="0"/>
            </sequence>
        </complexType>
    </element>
static get_sequenceinsertion(sequence: Sequence_, indent: int) str[source]

Return the insertion string required for the given sequence.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> from hydpy import prepare_model
>>> model = prepare_model("hland_96")
>>> print(XSDWriter.get_sequenceinsertion(model.sequences.fluxes.pc, 1))
    <element
        name="pc"
        minOccurs="0"/>
classmethod get_readerwriterinsertion(type_: Literal['reader', 'writer'], indent: int) str[source]

Return the insertion all sequences relevant for reading or writing time series data.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> print(XSDWriter.get_readerwriterinsertion("reader", 1)) 
    <complexType name="readerType">
        <sequence>
            <element name="node"
                     type="hpcb:node_readerType"
                     minOccurs="0"/>
            <element name="dummy_interceptedwater"
                     type="hpcb:dummy_interceptedwater_readerType"
                     minOccurs="0"/>
...
            <element name="wland_wag"
                     type="hpcb:wland_wag_readerType"
                     minOccurs="0"/>
        </sequence>
    </complexType>

>>> print(XSDWriter.get_readerwriterinsertion("writer", 1)) 
    <complexType name="writerType">
        <sequence>
            <element name="node"
                     type="hpcb:node_writerType"
                     minOccurs="0"/>
            <element name="arma_rimorido"
                     type="hpcb:arma_rimorido_writerType"
                     minOccurs="0"/>
...
            <element name="wq_trapeze_strickler"
                     type="hpcb:wq_trapeze_strickler_writerType"
                     minOccurs="0"/>
        </sequence>
    </complexType>
classmethod get_exchangeinsertion() str[source]

Return the complete string related to the definition of exchange items to be inserted into the string of the template file.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> print(XSDWriter.get_exchangeinsertion())  
    <complexType name="arma_rimorido_mathitemType">
...
    <element name="setitems">
...
    <complexType name="arma_rimorido_setitemsType">
...
    <element name="additems">
...
    <element name="multiplyitems">
...
    <element name="getitems">
...
classmethod get_mathitemsinsertion(indent: int) str[source]

Return a string defining a model-specific XML type extending ItemType.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> print(XSDWriter.get_mathitemsinsertion(1))  
    <complexType name="arma_rimorido_mathitemType">
        <complexContent>
            <extension base="hpcb:mathitemType">
                <choice>
                    <element name="control.responses"/>
...
                    <element name="fluxes.qout"/>
                </choice>
            </extension>
        </complexContent>
    </complexType>

    <complexType name="conv_idw_mathitemType">
...
classmethod get_keyworditemsinsertion(indent: int) str[source]

Return a string defining additional types that support modifying parameter values by specific keyword arguments.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> print(XSDWriter.get_keyworditemsinsertion(1))  
    <simpleType name="lland_control_kapgrenz_keywordType">
        <restriction base="string">
            <enumeration value="option"/>
        </restriction>
    </simpleType>

    <complexType name="lland_control_kapgrenz_setitemType">
        <complexContent>
            <extension base="hpcb:setitemType">
                <sequence>
                    <element name="keyword"
                             type="hpcb:lland_control_kapgrenz_keywordType"
                             minOccurs = "0"/>
                </sequence>
            </extension>
        </complexContent>
    </complexType>
...
classmethod get_itemsinsertion(itemgroup: str, indent: int) str[source]

Return a string defining the XML element for the given exchange item group.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> print(XSDWriter.get_itemsinsertion("setitems", 1))  
    <element name="setitems">
        <complexType>
            <sequence>
                <element ref="hpcb:selections"
                         minOccurs="0"/>
...
                <element name="hland_96"
                         type="hpcb:hland_96_setitemsType"
                         minOccurs="0"
                         maxOccurs="unbounded"/>
...
                <element name="nodes"
                         type="hpcb:nodes_setitemsType"
                         minOccurs="0"
                         maxOccurs="unbounded"/>
            </sequence>
            <attribute name="info" type="string"/>
        </complexType>
    </element>
classmethod get_itemtypesinsertion(itemgroup: str, indent: int) str[source]

Return a string defining the required types for the given exchange item group.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> print(XSDWriter.get_itemtypesinsertion(
...     "setitems", 1))  
    <complexType name="arma_rimorido_setitemsType">
...
    </complexType>

    <complexType name="dam_v001_setitemsType">
...
    <complexType name="nodes_setitemsType">
...
classmethod get_itemtypeinsertion(itemgroup: str, modelname: str, indent: int) str[source]

Return a string defining the required types for the given combination of an exchange item group and an application model.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> print(XSDWriter.get_itemtypeinsertion(
...     "setitems", "hland_96", 1))  
    <complexType name="hland_96_setitemsType">
        <sequence>
            <element ref="hpcb:selections"
                     minOccurs="0"/>
            <element name="control"
                     minOccurs="0"
                     maxOccurs="unbounded">
...
        </sequence>
    </complexType>
classmethod get_nodesitemtypeinsertion(itemgroup: str, indent: int) str[source]

Return a string defining the required types for the given combination of an exchange item group and Node objects.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> print(XSDWriter.get_nodesitemtypeinsertion(
...     "setitems", 1))  
    <complexType name="nodes_setitemsType">
        <sequence>
            <element ref="hpcb:selections"
                     minOccurs="0"/>
            <element name="sim"
                     type="hpcb:setitemType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
            <element name="obs"
                     type="hpcb:setitemType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
            <element name="sim.series"
                     type="hpcb:setitemType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
            <element name="obs.series"
                     type="hpcb:setitemType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
        </sequence>
    </complexType>
classmethod get_subgroupsiteminsertion(itemgroup: str, modelname: str, indent: int) str[source]

Return a string defining the required types for the given combination of an exchange item group and an application model.

>>> from hydpy.auxs.xmltools import XSDWriter
>>> print(XSDWriter.get_subgroupsiteminsertion(
...     "setitems", "hland_96", 1))  
    <element name="control"
             minOccurs="0"
             maxOccurs="unbounded">
...
    </element>
    <element name="inputs"
...
    <element name="factors"
...
    <element name="fluxes"
...
    <element name="states"
...
classmethod get_subgroupiteminsertion(itemgroup: str, model: modeltools.Model, subgroup: variabletools.SubVariables[Any, Any, Any], indent: int) str[source]

Return a string defining the required types for the given combination of an exchange item group and a specific variable subgroup of an application model or class Node.

Note that for setitems and getitems setitemType and getitemType are referenced, respectively, and for all others, the model-specific mathitemType:

>>> from hydpy import prepare_model
>>> model = prepare_model("hland_96")
>>> from hydpy.auxs.xmltools import XSDWriter
>>> print(XSDWriter.get_subgroupiteminsertion(  
...     "setitems", model, model.parameters.control, 1))
    <element name="control"
             minOccurs="0"
             maxOccurs="unbounded">
        <complexType>
            <sequence>
                <element ref="hpcb:selections"
                         minOccurs="0"/>
                <element name="area"
                         type="hpcb:setitemType"
                         minOccurs="0"
                         maxOccurs="unbounded"/>
                <element name="nmbzones"
...
            </sequence>
        </complexType>
    </element>
>>> print(XSDWriter.get_subgroupiteminsertion(  
...     "getitems", model, model.parameters.control, 1))
    <element name="control"
...
                <element name="area"
                         type="hpcb:getitemType"
                         minOccurs="0"
                         maxOccurs="unbounded"/>
...
>>> print(XSDWriter.get_subgroupiteminsertion(  
...     "additems", model, model.parameters.control, 1))
    <element name="control"
...
                <element name="area"
                         type="hpcb:hland_96_mathitemType"
                         minOccurs="0"
                         maxOccurs="unbounded"/>
...
>>> print(XSDWriter.get_subgroupiteminsertion(  
...     "multiplyitems", model, model.parameters.control, 1))
    <element name="control"
...
                <element name="area"
                         type="hpcb:hland_96_mathitemType"
                         minOccurs="0"
                         maxOccurs="unbounded"/>
...

For sequence classes, additional “series” elements are added:

>>> print(XSDWriter.get_subgroupiteminsertion(  
...     "setitems", model, model.sequences.factors, 1))
    <element name="factors"
...
                <element name="tc"
                         type="hpcb:setitemType"
                         minOccurs="0"
                         maxOccurs="unbounded"/>
                <element name="tc.series"
                         type="hpcb:setitemType"
                         minOccurs="0"
                         maxOccurs="unbounded"/>
                <element name="fracrain"
...
            </sequence>
        </complexType>
    </element>