Additional Functionality#

This section provides information on some additional functionality of the API that is not specific to any single class.

Difference and equivalence methods#

When working with the API, it is often useful to understand whether two instances of a class are equal, or if not, what the differences are. In general, the API considers two instances equal if they contain the exact same data and therefore would write the same output. Some attributes such as the filepath do not need to be the same for them to be considered equal.

Two instances of the same class can now be tested using == to check whether they are equal.

In [4]: from floodmodeller_api import DAT

In [5]: dat_a = DAT("EX18.DAT")

In [6]: dat_b = DAT("EX18.DAT")

In [7]: dat_a == dat_b
Out[7]: True

# Make some changes to one
In [8]: dat_a.sections["S3"].dist_to_next += 20

In [9]: dat_a.general_parameters["Min Depth"] = 0.2

In [10]: dat_a == dat_b
Out[10]: False

In addition, a detailed breakdown of any differences can be found using the .diff() method:

In [11]: dat_a.diff(dat_b)  # prints a list of differences to terminal
Files not equivalent, 3 difference(s) found:
  DAT->general_parameters->Min Depth:  0.2 != 0.1
  DAT->sections->S3->RIVER.SECTION.S3->dist_to_next:  120.0 != 100.0
  DAT->_all_units->itm[26]->RIVER.SECTION.S3->dist_to_next:  120.0 != 100.0

Currently, the == and .diff() methods is supported for the following classes:

  • DAT

  • IED

  • IEF

  • INP

  • XML2D

  • All 1D River Unit classes

File Backups#

The API automatically backs up any data files you load via the DAT, IED, IEF, INP and XML2D classes. The files are backed up in your OS temporary directory (see tempfile.gettempdir()). You can restore backups via the the .file.restore() method. Currently this restores the latest backup, but if you want to restore a specific backup then you list the backups and navigate to the file via the os file directory.

# Load the DAT
# Automatically backs up the file if it has changes since the last backup
dat = DAT("a_dat_file.DAT")
# List the available backups
backups = dat.file.list_backups()
# Restore the latest backup to a file
backups[0].restore(to = "restore-file.DAT")
# Restore an older backup
backups[6].restore(to = "restore-file.DAT")

JSON methods#

Any flood modeller object can be converted to a JavaScript Object Notation (JSON) string, and vice versa. To convert to JSON, simply call the .to_json() method on any API class to return a valid json string. Conversely, any valid json string produced by the API can be converted back into its equivalent API instance using the .from_json() constructor on any API class.

To convert a flood modeller object to a JSON string:

In [12]: from floodmodeller_api import IEF

In [13]: ief = IEF("network.ief")

In [14]: json_string = ief.to_json()

In [15]: print(json_string)
{
  "API Class": "floodmodeller_api.ief.IEF",
  "API Version": "0.5.0.post1",
  "Object Attributes": {
    "_filepath": "network.ief",
    "file": {
      "API Class": "floodmodeller_api.backup.File",
      "Object Attributes": {
        "path": "network.ief",
        "ext": ".ief",
        "dttm_str": "2024-10-28-11-05-20",
        "file_id": "8ed335be0d71749e3e4d857500058bf6ec105451",
        "backup_filename": "8ed335be0d71749e3e4d857500058bf6ec105451_2024-10-28-11-05-20.ief",
        "temp_dir": "C:\\Users\\PIERCEJA\\AppData\\Local\\Temp",
        "backup_dirname": "floodmodeller_api_backup",
        "backup_dir": "C:\\Users\\PIERCEJA\\AppData\\Local\\Temp\\floodmodeller_api_backup",
        "backup_csv_path": "C:\\Users\\PIERCEJA\\AppData\\Local\\Temp\\floodmodeller_api_backup\\file-backups.csv"
      }
    },
    "_ief_properties": [
      "[ISIS Event Header]",
      "Title",
      "Datafile",
      "[ISIS Event Details]",
      "RunType",
      "InitialConditions",
      "Start",
      "Finish",
      "Timestep",
      "SaveInterval",
      "Dflood",
      "Slot",
      "RefineBridgeSecProps",
      "SolveDHEqualsZeroAtStart",
      "RulesAtTimeZero",
      "RulesOnFirstIteration",
      "ResetTimesAfterPos",
      "UseFPSModularLimit",
      "UseRemoteQ",
      "2DFLOW"
    ],
    "EventData": {},
    "flowtimeprofiles": [],
    "Title": "network",
    "Datafile": "network.dat",
    "RunType": "Unsteady",
    "InitialConditions": "",
    "Start": 0,
    "Finish": 15,
    "Timestep": 20,
    "SaveInterval": 300,
    "Dflood": 1,
    "Slot": 1,
    "RefineBridgeSecProps": 0,
    "SolveDHEqualsZeroAtStart": 1,
    "RulesAtTimeZero": 1,
    "RulesOnFirstIteration": 0,
    "ResetTimesAfterPos": 1,
    "UseFPSModularLimit": 1,
    "UseRemoteQ": 1,
    "2DFLOW": 1,
    "_format_group_line_breaks": false,
    "_format_equals_spaced": false,
    "_log_path": "network.lf1"
  }
}

To convert a JSON file to a flood modeller object:

In [16]: ief = IEF.from_json(json_string)

In [17]: ief
Out[17]: <floodmodeller_api Class: IEF(filepath=network.ief)>

To convert a single River Section unit to JSON:

In [18]: from floodmodeller_api import DAT

In [19]: dat = DAT("EX18.DAT")

In [20]: river_unit_json = dat.sections["S3"].to_json()

In [21]: print(river_unit_json)
{
  "API Class": "floodmodeller_api.units.sections.RIVER",
  "API Version": "0.5.0.post1",
  "Object Attributes": {
    "_label_len": 12,
    "_subtype": "SECTION",
    "_name": "S3",
    "spill1": "S3LS",
    "spill2": "",
    "lat1": "",
    "lat2": "",
    "lat3": "",
    "lat4": "",
    "comment": "",
    "dist_to_next": 100.0,
    "slope": 0.0001,
    "density": 1000.0,
    "nrows": 5,
    "_data": {
      "class": "pandas.DataFrame",
      "object": {
        "X": {
          "0": 0.0,
          "1": 0.1,
          "2": 1.0,
          "3": 2.0,
          "4": 2.1
        },
        "Y": {
          "0": 20.0,
          "1": 18.0,
          "2": 18.0,
          "3": 18.0,
          "4": 20.0
        },
        "Mannings n": {
          "0": 0.03,
          "1": 0.03,
          "2": 0.03,
          "3": 0.03,
          "4": 0.03
        },
        "Panel": {
          "0": false,
          "1": false,
          "2": false,
          "3": false,
          "4": false
        },
        "RPL": {
          "0": 1.0,
          "1": 1.0,
          "2": 1.0,
          "3": 1.0,
          "4": 1.0
        },
        "Marker": {
          "0": "",
          "1": "",
          "2": "",
          "3": "",
          "4": ""
        },
        "Easting": {
          "0": 0.0,
          "1": 0.0,
          "2": 0.0,
          "3": 0.0,
          "4": 0.0
        },
        "Northing": {
          "0": 0.0,
          "1": 0.0,
          "2": 0.0,
          "3": 0.0,
          "4": 0.0
        },
        "Deactivation": {
          "0": "",
          "1": "",
          "2": "",
          "3": "",
          "4": ""
        },
        "SP. Marker": {
          "0": 0,
          "1": 0,
          "2": 0,
          "3": 0,
          "4": 0
        }
      }
    },
    "_active_data": null
  }
}

Quick methods to reading files#

In most cases you can load a file using the specific class for that filetype, e.g. loading a DAT file with dat = DAT("path_to_dat_file.dat"). It is also possible to use the handy read_file() function to load any supported Flood Modeller file. You may want to do this for example to iterate over many Flood Modeller files and produce a json export or save them with a new naming convention etc.

In [22]: for file in ["EX18.DAT", "Constant QT.ief", "DefenceBreach.xml", "Baseline_unchecked.csv"]:
   ....:     fm_object = floodmodeller_api.read_file(file)
   ....:     print(fm_object)
   ....: 
<floodmodeller_api Class: DAT(filepath=EX18.DAT)>
<floodmodeller_api Class: IEF(filepath=Constant QT.ief)>
<floodmodeller_api Class: XML2D(filepath=DefenceBreach.xml)>
<floodmodeller_api Class: HydrologyPlusExport(filepath=Baseline_unchecked.csv)>
floodmodeller_api.read_file(filepath: str | Path) FMFile#

Helper function to create an instance of an API class based on the provided filepath.

This function maps file suffixes to specific classes and returns an instance of the corresponding class for handling the file.

Parameters:

filepath (Union[str, Path]) – The path to the file to be read, as a string or Path object.

Returns:

An instance of the class corresponding to the file type identified by the file suffix.

Return type:

FMFile

Raises:

ValueError – If the file suffix does not correspond to any supported file type.

Example

from floodmodeller_api import read_file

ief = read_file("/path/to/file.ief")