Extracting Material and Soil Data#
Material and soil data are stored in a database class, similar to the bc_dbase class, and can be worked with in a similar way to the previous example (Working With Boundary Data in the bc_dbase.csv).
Viewing the Material File#
In this example, we will look at how to view the material file using EG00_001.tcf
from the
TUFLOW Example Model Dataset.
>>> from pytuflow import TCF
>>> tcf = TCF('path/to/EG00_001.tcf')
>>> mat = tcf.mat_file()
>>> print(mat.df)
Manning's n Rainfall Losses Land Use Hazard ID
Material ID
1 0.060 NaN NaN
2 0.022 NaN NaN
3 0.400 NaN NaN
4 0.030 NaN NaN
10 0.080 NaN NaN
11 0.040 NaN NaN
In the above example, we first get an instance of the material file using the
TCF.mat_file()
method. The material file is stored in a
MatDatabase
instance, which is similar to the
BCDatabase
class, and stores the database content in a pandas DataFrame which
can be accessed via the MatDatabase.df
attribute.
The value for a given material ID can be accessed using the MatDatabase.value()
method:
>>> mat.value(1)
0.06
In this case, the method isn’t doing anything special, as the same result could be achieved by using the DataFrame:
>>> mat.df.loc[1, "Manning's n"]
np.float64(0.06)
However, the MatDatabase.value()
method becomes useful in more complex cases,
such as when the given material is using a depth-varying manning’s n value. Consider the following example using
EG07_012.tcf
from the TUFLOW example models:
>>> tcf = TCF('path/to/EG07_012.tcf')
>>> mat = tcf.mat_file()
>>> print(mat.df)
Manning's n Rainfall Losses Landuse Hazard ID Description
ID
1 0.03,0.1,0.1,0.06 0,0 NaN NaN
2 0.02 0,0 NaN NaN
3 0.03,0.02,0.1,0.4 0,0 NaN NaN
4 0.03 0,0 NaN NaN
10 0.03,0.01,0.1,0.08 0,0 NaN NaN
11 0.03,0.1,0.1,0.04 0,0 NaN NaN
The manning’s n value for some of the materials is a list of values signifying a depth-varying value. When
this value is extracted using the MatDatabase.value()
method, it will return a
this in a more readable format within a DataFrame:
>>> mat.value(1)
Depth Manning's n
0 0.03 0.10
1 0.10 0.06
This is also true if the depth varying values are stored in a different CSV file and referenced in the material file.
The MatDatabase.value()
method will automatically read the CSV file and
return the values in a DataFrame format.
Viewing the Soil File#
The soil file is very similar to the material file. Let’s have a look at EG05_006.tcf
from the TUFLOW
example models:
>>> tcf = TCF('path/to/EG05_006.tcf')
>>> soil = tcf.soils_file()
>>> print(soil.df)
Method Column 1 Column 2
Soil ID
1 GA "CLAY"
2 GA "SILTY CLAY"
3 GA "SANDY CLAY"
4 GA "CLAY LOAM"
5 GA "SILTY CLAY LOAM"
6 GA "SANDY CLAY LOAM"
7 GA "SILT LOAM"
8 GA "LOAM"
9 GA "SANDY LOAM"
10 GA "LOAMY SAND"
11 GA "SAND"
12 NONE NaN NaN
Similar to the material file and bc_dbase, the soil file is stored as as database class, and the data can
be accessed using the SoilDatabase.df
attribute.
The soil database is different, and a bit more awkward than the other databases as the columns change depending
on the method used, or they can even be different for the same method. For example, the "GA"
(Green-Ampt)
method expects the first column to be the name of the USDA soil type, or it can be the
“Suction” parameter for the Green-Ampt method. If the method is "ILCL"
, then the first column is the
initial loss value. Because of this, the DataFrame uses generic column names, such as “Column 1” and “Column 2”.
The value method comes in handy here, as it will return the values with named keys based on the method used.
>>> soil.value(1)
CaseInsDictOrdered([('method', 'GA'),
('USDA Soil Type', 'CLAY'),
('Initial Moisture', None),
('Max Ponding Depth', None),
('Horizontal Conductivity', None),
('Residual Water Content', None),
('Saturated Water Content', None),
('alpha', None),
('n', None),
('L', None)])
The returned value is an ordered dictionary that also uses case-insensitive keys, so you can access the values
using named parameters, such as "Horizontal Conductivity"
, rather than the generic “Column 1” or “Column 2”.
We can look at EG05_011.tcf
to see an example of a more complex soil file:
>>> tcf = TCF('path/to/EG05_011.tcf')
>>> soil = tcf.soils_file()
>>> print(soil.df)
Method Column 1 Column 2 Column 3 Column 4 Column 5
Soil ID
1 GA 316.3 0.3 0.385 0.2 0.2
2 GA 292.2 0.5 0.423 0.2 0.2
3 GA 239.0 0.6 0.321 0.2 0.2
4 GA 208.8 1.0 0.309 0.2 0.2
5 GA 273.0 1.0 0.432 0.2 0.2
6 GA 218.5 1.5 0.330 0.2 0.2
7 GA 166.8 3.4 0.486 0.2 0.2
8 GA 88.9 7.6 0.434 0.2 0.2
9 GA 110.1 10.9 0.412 0.2 0.2
10 GA 61.3 29.9 0.401 0.2 0.2
11 GA 49.5 117.8 0.417 0.2 0.2
12 NONE NaN NaN NaN NaN NaN
>>> print(soil.value(1))
CaseInsDictOrdered([('method', 'GA'),
('Suction', 316.3),
('Hydraulic Conductivity', 0.3),
('Porosity', 0.385),
('Initial Moisture', 0.2),
('Max Ponding Depth', 0.2),
('Horizontal Conductivity', None),
('Residual Water Content', None),
('Saturated Water Content', None),
('alpha', None),
('n', None),
('L', None)])
This example is still relatively simple, in that all the soils use the same method. However, you can imagine a situation
where different soil methods are used and this would require mapping from column names to a method-specific,
or method context-specific, parameter. Rather than the user checking whether “Column 1” is a string or a number,
the SoilDatabase.value()
method will return the values in a dictionary with
specific keys based on the method used. So, for example, the user can check if the key “USDA Soil Type” exists:
>>> soil_1 = soil.value(1)
>>> if soil_1['method'] == 'GA' and 'USDA Soil Type' in soil_1:
... print("This soil uses the GA method with a USDA Soil Type.")
... elif soil_1['method'] == 'GA':
... print("This soil type uses the GA method with custom parameters.")
... else:
... print("This soil type does not use the GA method.")
This soil type uses the GA method with custom parameters.