XML2D Class#

Summary#

The XML2D class is used to read and update Flood Modeller’s 2D XML file format. The class is initiated with the full filepath of an xml file to load an existing 2D model.

Attention

The API functionality for 2D XML files is currently in development and should be treated as experimental.

New in version 0.4.1

2D elements can now be added and removed from an XML2D instance by simply adding/removing them from the relevant section

from floodmodeller_api import XML2D

model = XML2D('path/to/2d_model.xml') # Loads existing XML file into memory

Once you have initialised an XML class, all the information defining the model will be stored in the following attributes (some of these attributes may not be present in the xml file and will therefore return None )

  • .name - 2D Model name

  • .link1d - A list of 1 or more 1D links, each containing a dictionary of parameters including the link shapefile and ief file.

  • .logfile - Location of model log

  • .domains - A dictionary of model domains, with each domain_id as the keys. Each model domain is then a nested dictionary of categories and values.

  • .restart_options

  • .advanced_options

  • .processor

  • .unit_system

  • .description

There are many different parameters which can be set in a 2D model. All of these are able to be read via the XML2D class if they appear in the xml file. Within each main attribute, the naming and structure of options is consistent with the structure in the xml file itself. In cases where an option has just a single value, the value and option name will appear as a key-pair in the dictionary. In cases where an option has attributes as well as a value, the attributes will also appear, and the value will be accessible through the ‘value’ key.

Any option where multiple values can be provided (e.g. topography files) will be present as a list of dictionaries, whereas options where only one value can be required will be a single dictionary.

A typical example of the available options for a single 2D domain is shown below:

model = XML2D('path/to/2d_model.xml')

# Access a specific model domain by name
model.domains["Domain1 20m Q"]
>>>
    {
        "domain_id": "Domain1 20m Q",
        "computational_area": {
            "xll": 538000.0,
            "yll": 177000.0,
            "dx": 20,
            "nrows": 200,
            "ncols": 300,
            "active_area": "GIS\\Active_Area1.shp",
            "rotation": 0
        },
        "topography": ["GIS\\5M_DTM_1.asc"],
        "time": {
            "start_time": "00:00:00",
            "start_date": "1/1/2000",
            "total": {
                "unit": "second",
                "value": 43200
            }
        },
        "run_data": {
            "time_step": 2,
            "scheme": "ADI"
        },
        "initial_conditions": {
            "type": "globalwaterlevel",
            "value": 0.0
        },
        "roughness": [
            {
                "law": "manning",
                "type": "global",
                "value": 0.05
            }
        ],
        "output_results": {
            "output": [
                {
                    "output_id": "",
                    "format": "SMS9",
                    "variables": "DepthVelocityElevationFlow",
                    "frequency": 300
                }
            ],
            "massfile": {
                "frequency": "10",
                "value": "Domain1+2_QH_2DMB_1.csv"
            }

Accessing individual elements can be achieved by using the relevant keys:

model.domains["Domain1 20m Q"]["computational_area"]["dx"]
>>> 20

Any element can be updated by simply updating editing the value in the dictionary. For example to change the 1d link shapefile:

model.link1d[0]["link"]
>>> 'GIS\\Link1+2_QH.shp'

model.link1d[0]["link"] = "GIS\\Link3_New.shp"

Information on all the possible options for 2D XML files can be derived from the xml schema file here. Any edits to 2D XML files are first validated against this schema before saving, an exception will be raised if the data is not valid.

An XML2D instance can be updated in place and saved in the same way as for all other files supported by the API using the .update() and .save() methods respectively.

Add and remove functionality#

We can update the xml file directly from the API by adding and removing properties. Imagine that we start with an almost blank xml file that passes the validation,

model = XML2D()

First we can change a variable that already exists. For instance we can change the value of the topography,

model.domains[domain_name]["topography"] = 'path/to/my_topography.asc'

We can edit any value that is already in the xml tree in the same way by overwritting it, another example is we can change the end time of the computation,

model.domains[domain_name]["time"]["total"] = 1.00

We can also add information to a key that does not exist yet, such as roughness. We first begin by defining an empty list and then populate it with a dictionary, we can keep appending so we have as many dictionaries in a list as we want,

model.domains[domain_name]["roughness"] = [] # created an empty list we can append dictionaries to
model.domains[domain_name]["roughness"].append(
    {'type': 'file', 'law': 'manning', 'value': 'path/to/my_roughness_file.shp'}
)
# adding second roughness file.
model.domains[domain_name]["roughness"].append(
    {'type': 'file', 'law': 'manning', 'value': 'path/to/my_second_roughness_file.shp'}
)

If we wanted to edit one of the roughness values then we would need to use the list indexing, to change the file for the first roughness,

model.domains[domain_name]["roughness"][0]["value"] = 'path/to/my_new_roughness_file.shp'

To remove values or keys from the xml file we can use del ... followed by the part you want to remove. If we want to remove the second roughness entry for instance then,

del model.domains[domain_name]["roughness"][1]

Further, we can remove all information relating to the key roughness,

del model.domains[domain_name]["roughness"]

The xml2d files should follow the Flood Modeller xsd schema - preferably the most recent version but backwards compatability is possible.

Reference#

class floodmodeller_api.XML2D(xml_filepath: str | Path | None = None, from_json: bool = False)#

Reads and write Flood Modeller 2D XML format ‘.xml’

Parameters:

xml_filepath (str, optional) – Full filepath to xml file.

Output:

Initiates ‘XML2D’ class object

Raises:
  • TypeError – Raised if xml_filepath does not point to a .xml file

  • FileNotFoundError – Raised if xml_filepath points to a file which does not exist

update() None#

Updates the existing XML based on any altered attributes

save(filepath: str | Path | None)#

Saves the XML to the given location, if pointing to an existing file it will be overwritten. Once saved, the XML() class will continue working from the saved location, therefore any further calls to XML.update() will update in the latest saved location rather than the original source XML used to construct the class

Parameters:

filepath (str) – Filepath to new save location including the name and ‘.xml’ extension

Raises:

TypeError – Raised if given filepath doesn’t point to a file suffixed ‘.xml’

diff(other: XML2D, force_print: bool = False) None#

Compares the XML2D class against another XML2D class to check whether they are equivalent, or if not, what the differences are. Two instances of a XML2D class are deemed equivalent if all of their attributes are equal except for the filepath and raw data. For example, two XML2D files from different filepaths that had the same data except maybe some differences in decimal places and some default parameters ommitted, would be classed as equaivalent as they would produce the same XML2D instance and write the exact same data.

The result is printed to the console. If you need to access the returned data, use the method XML2D._get_diff()

Parameters:
  • other (floodmodeller_api.XML2D) – Other instance of a XML2D class

  • force_print (bool) – Forces the API to print every difference found, rather than just the first 25 differences. Defaults to False.

simulate(method: str = 'WAIT', raise_on_failure: bool = True, precision: str = 'DEFAULT', enginespath: str = '', console_output: str = 'simple', range_function: ~typing.Callable = <function trange>, range_settings: dict | None = None) Popen | None#

Simulate the XML2D file directly as a subprocess.

Parameters:
  • method (str, optional) – {‘WAIT’} | ‘RETURN_PROCESS’ ‘WAIT’ - The function waits for the simulation to complete before continuing (This is default) ‘RETURN_PROCESS’ - The function sets the simulation running in background and immediately continues, whilst returning the process object. Defaults to ‘WAIT’.

  • raise_on_failure (bool, optional) – If True, an exception will be raised if the simulation fails to complete without errors. If set to False, then the script will continue to run even if the simulation fails. If ‘method’ is set to ‘RETURN_PROCESS’ then this argument is ignored. Defaults to True.

  • precision (str, optional) – {‘DEFAULT’} | ‘SINGLE’ | ‘DOUBLE’ Define which engine to use for simulation, if set to ‘DEFAULT’ it will use the precision specified in the IEF. Alternatively, this can be overwritten using ‘SINGLE’ or ‘DOUBLE’.

  • enginespath (str, optional) – {‘’} | ‘/absolute/path/to/engine/executables’ Define where the engine executables are located. This replaces the default location (usual installation folder) if set to anything other than ‘’.

  • console_output (str, optional) – {‘simple’} | ‘standard’ | ‘detailed’ ‘simple’ - A simple progress bar for the simulation is presented in the console ‘standard’ - The standard Flood Modeller 2D output is presented in the console ‘detailed’ - The most detailed Flood Modeller 2D output is presented in the console Defaults to ‘WAIT’.

Raises:

UserWarning – Raised if ief filepath not already specified

Returns:

If method == ‘RETURN_PROCESS’, the Popen() instance of the process is returned.

Return type:

subprocess.Popen()

to_json() str#

Converts the object instance into a JSON string representation.

Returns:

A JSON string representing the object instance.

Return type:

str

classmethod from_json(json_string: str)#

Creates an object instance from a JSON string.

Parameters:

json_string (str) – A JSON string representation of the object.

Returns:

An object instance of the class.

Examples#

Example 1 - Updating DTM file

This is a simple example showing how you would update the dtm referenced in the 2D model

# Import modules
from floodmodeller_api import XML2D

# Initialise DAT class
model = XML2D("path/to/2d_model.xml")

# Define new dtm data path
new_dtm = "GIS/new_dtm.asc"

# Iterate through all 2D domains
for _, domain in model.domains.items():
    domain["topography"][0] = new_dtm  # update the dtm file

model.save("path/to/2d_model_v2.xml") # Save to new location