Working with Inputs#
Inputs are important building blocks of TUFLOW models. They are used a lot in other examples, however are never explicitly covered. This page aims to go into a bit more detail about how inputs can be used.
The examples on this page use models from the TUFLOW Example Model Dataset.
Input Attributes#
Inputs have a number of attributes that are useful to know about.
1. files#
Each input has a files
attribute that is a list of all the files that are associated
with the input.
>>> from pytuflow import TCF
>>> tcf = TCF('path/to/EG00_001.tcf')
>>> inp = tcf.find_input('Read GRID Zpts')[0]
>>> for f in inp.files:
... print(f)
TUFLOW\runs\..\model\grid\DEM_SI_Unit_01.tif
Typically, the number of files associated with an input is one, however there are a few situations where there could be multiple:
The input references multiple input files, such as:
Read GIS Z Shape == gis\2d_zsh_L.shp | gis\2d_zsh_P.shp
.The input uses a variable which can be resolved to multiple files, such as:
Read GIS Z Shape == gis\2d_zsh_<<~s1~>>_R.shp
The GIS layer references a file in the attribute table. A typical example is a
1d_xs
input, but this can also be the case for a1d_nwk
layer that has a channel using the"M"
(matrix) type, which references a csv fle.
TuflowPath#
Most files are stored as Path
objects, however GIS files are stored as TuflowPath
objects. The TuflowPath
class is a subclass
of Path that has some additional functionality to handle GPKG file paths (e.g. gis\database.gpkg >> layer_name
).
>>> inp = tcf.find_input('2d_bc')[0]
>>> file = inp.files[0]
>>> file
TuflowWindowsPath(TUFLOW\runs\..\model\gis\2d_bc_EG00_001_L.shp)
>>> print(file.dbpath)
TUFLOW\runs\..\model\gis\2d_bc_EG00_001_L.shp
>>> print(file.lyrname)
2d_bc_EG00_001_L
The example above shows how to access a couple of useful attributes added in the TuflowPath
class. The
dbpath
attribute returns the file path to the GIS database. For shapefiles,
this is the file path to the shapefile, and for GPKG files, this is the file path to the GPKG database.
The lyrname
attribute returns the layer name in the GIS database. This is useful
for GPKGs, as the layer name is not necessarily the same as the GPKG file name.
TuflowPath objects also extend the glob()
method to allow for globbing of layers in GPKG files.
The below example uses a GPKG created from EG07_002.tcf
using the convert TUFLOW model GIS format tool in QGIS.
>>> from pytuflow import TuflowPath
>>> gpkg = TuflowPath('/path/to/EG07_002.gpkg')
>>> for file in gpkg.glob('>> 2d_zsh*'):
... print(file)
..\model\gis\EG07_002.gpkg >> 2d_zsh_EG07_002_L
..\model\gis\EG07_002.gpkg >> 2d_zsh_EG07_002_P
In the above example, we use >>
to indicate that we are looking for layers within the GPKG file. We use the
pattern 2d_zsh*
to match all layers that start with 2d_zsh
. The result is a list of
TuflowPath
objects that represent the layers in the GPKG file.
TuflowPath also has a couple of useful methods for extracting information from the GIS layer. The first example extracts the GIS attributes from the layer without requiring GDAL to be installed.
>>> from pytuflow import TCF
>>> tcf = TCF('path/to/EG00_001.tcf')
>>> gis_2d_bc = tcf.find_input('2d_bc')[0].files[0]
>>> for attr in gis_2d_bc.gis_attributes():
... print(attr)
OrderedDict({'Type': 'QT', 'Flags': '', 'Name': 'FC01', 'f': None, 'd': None, 'td': None, 'a': None, 'b': None})
OrderedDict({'Type': 'HQ', 'Flags': '', 'Name': '', 'f': None, 'd': None, 'td': None, 'a': None, 'b': 0.01})
The second example requires GDAL to be installed, and is a convenience method for opening the GIS layer with GDAL within a context manager.
>>> with gis_2d_bc.open_gis() as gis:
... print(gis.driver)
... print(gis.ds)
... print(gis.lyr)
<osgeo.ogr.Driver; proxy of <Swig Object of type 'OGRDriverShadow *' at 0x0000024A5FF8A520> >
<osgeo.ogr.DataSource; proxy of <Swig Object of type 'OGRDataSourceShadow *' at 0x000001E7CEC19A10> >
<osgeo.ogr.Layer; proxy of <Swig Object of type 'OGRLayerShadow *' at 0x000001E7CC8A0990> >
2. has_missing_files#
Inputs have a has_missing_files
attribute that indicates whether the input has
any missing files. This attribute can be useful when used with the find_input()
method to filter inputs that have missing files.
First, let’s modify the code input to remove the _R
suffix, this causes the file path to be incorrect.
>>> tcf = TCF('path/to/EG00_001.tcf')
>>> inp = tcf.find_input('2d_code')[0]
>>> inp.rhs = inp.rhs.replace('_R', '')
>>> print(inp)
Read GIS Code == gis\2d_code_EG00_001.shp
Then we can use the attrs
parameter of the find_input()
method to filter inputs that have missing files.
The attrs
parameter tells the filter to check the has_missing_files
attribute of each input.
If the attribute evaluates to True
, then the input will be returned.
>>> for inp in tcf.find_input(attrs='has_missing_files'):
... print(f'Input has missing files: {inp}')
Read GIS Code == gis\2d_code_EG00_001.shp
More than one attribute can be passed into the attrs
parameter.
For example, if you wanted to return only missing files from GIS inputs:
>>> from pytuflow import const
>>> for inp in tcf.find_input(attrs=[('has_missing_files',), ('TUFLOW_TYPE', const.INPUT.GIS)]):
... print(inp)
Read GIS Code == gis\2d_code_EG00_001.shp
In the above example, we import the const
module from pytuflow
which contains constants for TUFLOW types.
We then pass in a list of tuples to the attrs
parameter. Each tuple contains the attribute name and the value to filter on.
The default value for the attribute is True
, so we don’t need to specify it for the has_missing_files
attribute.
3. lhs, rhs, and value#
Inputs have a lhs
, rhs
, and value
attribute.
The lhs
attribute and the rhs
attribute are the left-hand
and right-hand sides of the input, respectively. They reflect what the command line would look like in the text editor.
The value
attribute is a resolved value (if possible) version of the
rhs
attribute in an appropriate data type. For example, the returned value will
be an integer if the command is setting the code value (Set Code == 0
), or a float if the command is setting
the model cell size (Cell Size == 2.5
), or a Path object if the command is referencing a file.
>>> tcf = TCF('path/to/EG00_001.tcf')
>>> inp = tcf.find_input('set code')[0]
>>> inp.lhs
'Set Code'
>>> inp.rhs
'0'
>>> inp.value
0
The lhs
and rhs
attributes can be edited by the user,
however the value
attribute is read-only.
>>> inp = tcf.find_input('cell size')[0]
>>> inp.value = 2.5
Traceback (most recent call last):
...
AttributeError: The "value" attribute is read-only, use "rhs" to set the value of the input.
>>> inp.rhs = '2.5'
>>> inp.value
2.5
The lhs
is also editable, but is restricted to the same input type. For example,
a Read GIS
command must stay as a Read GIS
command, and cannot change to a Set Code
command. The purpose
of editing the lhs
attribute is to allow easy insertion/editing of additional keywords in the
given command.
>>> inp = ... # assume input is loaded as "Time Output Cutoff Depth == 0.1"
>>> inp.lhs = 'Time Output Cutoff Hazard'
>>> print(inp)
Time Output Cutoff Hazard == 0.1
The above example changes the command, which adds an additional time output to the model, to be based on hazard instead of depth.
The value
attribute will also be resolved if possible. For example, if the rhs
of the command is set to a variable, and the variable has a global scope (i.e. is not scenario or event dependent),
then the value
attribute will return the resolved value of the variable.
To show this, let’s first insert a new variable into the TCF after the sgs sample target distance
input.
>>> tcf = TCF('path/to/EG00_001.tcf')
>>> ref_inp = tcf.find_input('sgs sample target distance')[0]
>>> tcf.insert_input(ref_inp, 'Set Variable CELL_SIZE == 2.5', after=True)
Then, let’s change the rhs
of the Cell Size
command to reference the variable we just created.
>>> cell_size = tcf.find_input('cell size')[0]
>>> print(cell_size)
'Cell Size == 5.0'
>>> cell_size.rhs = '<<CELL_SIZE>>'
Finally, we can check the value
attribute to see the resolved value of the variable.
>>> print(cell_size.rhs)
<<CELL_SIZE>>
>>> print(cell_size.value)
2.5
As you can see in the above example, the rhs
attribute returns the variable name,
and the value
attribute returns the resolved value of the variable.