DAT Class#

Summary#

The DAT class is used to read, write and update Flood Modeller’s dat file format. The class is initiated with the full filepath of a DAT file to load an existing network. Alternatively, a new dat file can be created in memory by simply calling DAT() without passing in a file path.

New in version 0.4.1

1D units can now be added and removed from networks using the .insert_unit() and .remove_unit() methods

from floodmodeller_api import DAT

dat = DAT('path/to/datafile.dat') # Loads existing DAT file into memory
dat = DAT() # Creates a new blank DAT file in memory

Once you have initialised a DAT class, the various units can be accessed via the attributes:

In each, the units are stored in a dictionary of unit names and unit classes. Only units which are supported in the API will be accesible via these attributes, all of which can be found in the Individual Unit Classes section.

# Print string representation of all units.
print(dat.sections)
print(dat.conduits)
print(dat.structures)
print(dat.boundaries)
print(dat.losses)

Each individual unit class is somewhat unique in how they can be worked with in python, but generally most unit classes will have a .name, .comment and .data attribute. For example, a RIVER unit class contains the full section data as a dataframe:

dat.sections['S5'].data # Accessing the section data for river section 'S5'

>>>
    X     Y  Mannings n  Panel  RPL Marker  Easting  Northing Deactivation  SP. Marker
0  -10.0  10.0        0.03  False  0.0             0.0       0.0                        0
1   -9.0   9.0        0.03  False  0.0             0.0       0.0                        0
2   -8.0   8.0        0.03  False  0.0             0.0       0.0                        0
3   -7.0   7.0        0.03  False  0.0             0.0       0.0                        0
4   -6.0   6.0        0.03  False  0.0             0.0       0.0                        0
5   -5.0   5.0        0.03  False  0.0             0.0       0.0                        0
6   -4.0   4.0        0.03  False  0.0             0.0       0.0                        0
7   -3.0   3.3        0.03  False  0.0             0.0       0.0                        0
8   -2.0   3.3        0.03  False  0.0             0.0       0.0                        0
9   -1.0   3.3        0.03  False  0.0             0.0       0.0                        0
10   0.0   3.3        0.03  False  0.0             0.0       0.0                        0
11   1.0   3.3        0.03  False  0.0             0.0       0.0                        0
12   2.0   3.3        0.03  False  0.0             0.0       0.0                        0
13   3.0   3.3        0.03  False  0.0             0.0       0.0                        0
14   4.0   4.0        0.03  False  0.0             0.0       0.0                        0
15   5.0   5.0        0.03  False  0.0             0.0       0.0                        0
16   6.0   6.0        0.03  False  0.0             0.0       0.0                        0
17   7.0   7.0        0.03  False  0.0             0.0       0.0                        0
18   8.0   8.0        0.03  False  0.0             0.0       0.0                        0
19   9.0   9.0        0.03  False  0.0             0.0       0.0                        0
20  10.0  10.0        0.03  False  0.0             0.0       0.0                        0

All other associated data can be accessed and edited for a RIVER unit class via class attributes, for example the ‘distance to next section’ can be accessed using the .dist_to_next attribute:

print(dat.sections['S5'].dist_to_next) # print the distance to next section for river section 'S5'
>>> 105.0

dat.sections['S5'].dist_to_next = 150.0 # Update the distance to next section to 150m

It is possible to call the dat.next() and dat.prev() methods on a unit of any class to find the next or previous units in the reach:

print(dat.next(dat.sections['S5']))
>>> <floodmodeller_api Unit Class: RIVER(name=S6, type=SECTION)>

In this version of the API, dat.insert_unit() and dat.remove_unit() have been added, allowing to insert or remove one unit at a time from the dat file.

unit_S6 = dat.sections['S6']
dat.remove_unit(unit_S6) #remove unit S6 from dat file
dat.insert_unit(unit_S6, add_after = dat.sections['S5']) #add unit back into dat file

Although it is possible to rename units by passing a new name into the .name attribute, it is recommended to avoid this as it may cause label issues within the network.

For units that are not currently supported in the API, limited read-only access can be found in the dat._unsupported attribute, where unit names, types and labels can be accessed. The DAT representation of an unsupported unit can accessed but cannot be edited.

dat._unsupported
>>> {
        'S0 (RESERVOIR)': <floodmodeller_api Unit Class: RESERVOIR(name=S0, type=False)>,
        'S0 (WEIR)': <floodmodeller_api Unit Class: WEIR(name=S0, type=False)>,
        'S1u (JUNCTION)': <floodmodeller_api Unit Class: JUNCTION(name=S1u, type=OPEN)>,
        'C2m (MANHOLE)': <floodmodeller_api Unit Class: MANHOLE(name=C2m, type=False)>,
        'C2d (WEIR)': <floodmodeller_api Unit Class: WEIR(name=C2d, type=False)>,
        'S4 (WEIR)': <floodmodeller_api Unit Class: WEIR(name=S4, type=False)>,
        'S4_drop (JUNCTION)': <floodmodeller_api Unit Class: JUNCTION(name=S4_drop, type=OPEN)>,
        'S8 (WEIR)': <floodmodeller_api Unit Class: WEIR(name=S8, type=False)>,
        'P_suc (OCPUMP)': <floodmodeller_api Unit Class: OCPUMP(name=P_suc, type=False)>,
        'CSO (RESERVOIR)': <floodmodeller_api Unit Class: RESERVOIR(name=CSO, type=False)>
    }

print(dat._unsupported['C2m (MANHOLE)'])
>>> MANHOLE #revision#1
    C2m         C2md        C2mH
        20.5         3       1.7       0.9         0

In addition to the units, the general parameters for the DAT file can be accessed through the .general_parameters attribute. This contains a dictionary of all the general DAT settings and can be edited by assigning them new values.

Warning

Only change values in the general parameters which you are sure can be edited. For example, ‘Node Count’ should be treated as read-only

dat.general_parameters # Access dictionary of general DAT parameters
>>> {
        "Node Count": 14,
        "Lower Froude": 0.75,
        "Upper Froude": 0.9,
        "Min Depth": 0.1,
        "Convergence Direct": 0.001,
        "Units": "DEFAULT",
        "Water Temperature": 10.0,
        "Convergence Flow": 0.01,
        "Convergence Head": 0.01,
        "Mathematical Damping": 0.7,
        "Pivotal Choice": 0.1,
        "Under-relaxation": 0.7,
        "Matrix Dummy": 0.0,
        "RAD File": ""
    }

Within a unit, there is also support for logical RULES & VARRULES. There is also support for VARIABLES in the DAT file as well.

Warning

You can only use RULES, VARRULES & VARIABLES if your unit/file actually has them.

dat.structures["MINT_SLu"].rules
>>> {
        {"name": "Rule 1", "logic": "IF (LEVEL(KENT06_036...mer=ON\nEND"},
        {"name": "Rule 2", "logic": "IF (Level(KENT06_036...ESTART\nEND"},
        {"name": "Rule 3", "logic": "IF (Level(KENT06_036...VE = 0\nEND"}
    }

dat.structures["MINT_SLu"].varrules
>>> {
        {"name": "Varrule 1", "logic": "IF (Level(KENT06_036....RESET\nEND"},
        {"name": "Varrule 2", "logic": "IF (Level(KENT06_036....RESET\nEND"}
    }

dat.variables.data
>>> {
        Index(["name", "type", "initial value", "initial status"], dtype="object")
        0: array(["TravelTimer", "TIMER", "0", "0"], dtype=object)
        1: array(["DumVar", "integer", "", "n/a"], dtype=object)
    }

Reference#

class floodmodeller_api.DAT(dat_filepath: str | Path | None = None, with_gxy: bool = False, from_json: bool = False)#

Reads and write Flood Modeller datafile format ‘.dat’

Parameters:

dat_filepath (str, optional) – Full filepath to dat file. If not specified, a new DAT class will be created. Defaults to None.

Output:

Initiates ‘DAT’ class object

Raises:
  • TypeError – Raised if dat_filepath does not point to a .dat file

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

update() None#

Updates the existing DAT based on any altered attributes

save(filepath: str | Path) None#

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

Parameters:

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

Raises:

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

insert_unit(unit: Unit, add_before: Unit | None = None, add_after: Unit | None = None, add_at: int | None = None, defer_update: bool = False) None#

Inserts a unit into the dat file.

Parameters:
  • unit (Unit) – FloodModeller unit input.

  • add_before (Unit) – FloodModeller unit to add before.

  • add_after (Unit) – FloodModeller unit to add after.

  • add_at (integer) – Positional argument (starting at 0) of where to add in the dat file. To add at the end of the network you can use -1.

Raises:
  • SyntaxError – Raised if no positional argument is given.

  • TypeError – Raised if given unit isn’t an instance of FloodModeller Unit.

  • NameError – Raised if unit name already appears in unit group.

insert_units(units: list[Unit], add_before: Unit | None = None, add_after: Unit | None = None, add_at: int | None = None) None#

Inserts a list of units into the dat file.

Parameters:
  • units (list[Unit]) – List of FloodModeller units.

  • add_before (Unit) – FloodModeller unit to add before.

  • add_after (Unit) – FloodModeller unit to add after.

  • add_at (integer) – Positional argument (starting at 0) of where to add in the dat file. To add at the end of the network you can use -1.

remove_unit(unit: Unit) None#

Remove a unit from the dat file.

Parameters:

unit (Unit) – flood modeller unit input.

Raises:

TypeError – Raised if given unit isn’t an instance of FloodModeller Unit.

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

Compares the DAT class against another DAT class to check whether they are equivalent, or if not, what the differences are. Two instances of a DAT class are deemed equivalent if all of their attributes are equal except for the filepath and raw data. For example, two DAT 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 equivalent as they would produce the same DAT 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 DAT._get_diff()

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

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

next(unit: Unit) Unit | list[Unit] | None#

Finds next unit in the reach.

Next unit in reach can be infered by:

The next unit in the .dat file structure - such as when a river section has a positive distance to next The units with the exact same name - such as a junction unit The next unit as described in the ds_label - such as with Bridge units

Parameters:

unit (Unit) – flood modeller unit input.

Returns:

Flood modeller unit either on its own or in a list if more than one follows in reach.

Return type:

Union[Unit, list[Unit], None]

prev(unit: Unit) Unit | list[Unit] | None#

Finds previous unit in the reach.

Previous unit in reach can be infered by:

The previous unit in the .dat file structure - such as when the previous river section has a positive distance to next. The units with the exact same name - such as a junction unit The previous unit as linked through upstream and downstream labels - such as with Bridge units

Parameters:

unit (Unit) – flood modeller unit input.

Returns:

Flood modeller unit either on its own or in a list if more than one follows in reach.

Return type:

Union[Unit, list[Unit], None]

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 - Adding 300mm siltation to all river sections

In this example, the cross section data for individual river sections needs to be edited to add 300mm to the lowest bed level and make this the minimum bed level across the entire section. This is a simple method to quickly represent siltation in the channel. The updated DAT file is saved to a new location rather than updating the original file.

# Import modules
from floodmodeller_api import DAT

# Initialise DAT class
dat = DAT('path/to/datafile.dat')

# Iterate through all river sections
for name, section in dat.sections.items():
    df = section.data # get section data
    min_elevation = df['Y'].min() # Get minimum bed level across section
    raised_bed = min_elevation + 0.3 # Define new minimum bed level by adding 0.3m
    df['Y'].loc[df['Y'] < raised_bed] = raised_bed # Update any bed levels which are less than the new min bed level

dat.save('path/to/datafile_300mm_siltation.dat') # Save to new location

Example 2 - Inserting multiple units

In this example, multiple units from one DAT file are inserted into another DAT file.

# Import modules
from floodmodeller_api import DAT

# Initialise DAT class
dat_1 = DAT('path/to/datafile1.dat')
dat_2 = DAT('path/to/datafile2.dat')

# Insert units from dat_2 into dat_1
dat_1.insert_units(
    units=[dat_2.sections["20"], dat_2.sections["30"]],
    add_before=dat_1.sections["P4000"],
)

dat_1.save('path/to/new_datfile1.dat') # Save to new location