Catchment structure for the Lachlan valley¶
Network definition for a shapefile with information on the Lachlan valley, as of ~8th August 2025. This is use case for customisable column names as well as being more liberal with the types of columns in the geopandas
data frame resulting from reading the shapefile.
from pathlib import Path
import geopandas as gpd
from geosdhydro import ShapefileToSwiftConverter
fpath = Path.home() / "data"/"wnsw"/"Lachlan"/"Lachlan_links4swift.shp"
fpath.exists()
True
link_specs = gpd.read_file(fpath)
link_specs.head()
OBJECTID | Shape_Leng | LinkID | FromNodeID | ToNodeID | HeadLink | SPathCnt | LPathCnt | SPathLen | LPathLen | ... | Area_sqkm | SHORTNAME | Elevation | Shape_Le_1 | Shape_Le_2 | Shape_Area | DArea | NodeID | SubCatID | geometry | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0.146763 | 1 | 43408002 | 43407878 | 0 | 23 | 23 | 36156.428635 | 36156.428635 | ... | 76.225305 | CADIANGULLONG @ PAN. | 6.381 | 62604.167491 | 62604.167491 | 7.622530e+07 | 7.622146e+07 | 43408002.0 | 2.0 | LINESTRING (148.97972 -33.5148, 148.8481 -33.5... |
1 | 2 | 0.125647 | 2 | 43332557 | 43407878 | 0 | 22 | 22 | 26988.248489 | 26988.248489 | ... | 190.273377 | BELUBULA THE NEEDLES | 366.293 | 303059.700345 | 303059.700345 | 1.011929e+09 | 1.902571e+08 | 43332557.0 | 7.0 | LINESTRING (148.97361 -33.57389, 148.8481 -33.... |
2 | 5 | 0.038594 | 5 | 43323436 | 43407903 | 0 | 3 | 3 | 18098.684816 | 18098.684816 | ... | 360.595819 | LACHLAN R @ COWRA | 274.300 | 299445.505950 | 299445.505950 | 1.294608e+09 | 3.606294e+08 | 43323436.0 | 70.0 | LINESTRING (148.72056 -33.82222, 148.68359 -33... |
3 | 6 | 0.220645 | 6 | 43328702 | 43407903 | 0 | 25 | 25 | 40402.031075 | 40402.031075 | ... | 234.353118 | LACHLAN R @ COWRA | 274.300 | 299445.505950 | 299445.505950 | 1.294608e+09 | 2.343552e+08 | 43328702.0 | 76.0 | LINESTRING (148.87306 -33.94639, 148.68359 -33... |
4 | 7 | 0.254465 | 7 | 43636627 | 43407903 | 0 | 32 | 32 | 49606.117846 | 49606.117846 | ... | 340.169996 | HOVELLS CK @ NO.2 | 323.000 | 174352.740146 | 174352.740146 | 3.401700e+08 | 3.401840e+08 | 43636627.0 | 20.0 | LINESTRING (148.87246 -34.00384, 148.68359 -33... |
5 rows × 29 columns
{x: link_specs[x].dtype for x in link_specs.columns}
{'OBJECTID': dtype('int64'), 'Shape_Leng': dtype('float64'), 'LinkID': dtype('int64'), 'FromNodeID': dtype('int64'), 'ToNodeID': dtype('int64'), 'HeadLink': dtype('int32'), 'SPathCnt': dtype('int64'), 'LPathCnt': dtype('int64'), 'SPathLen': dtype('float64'), 'LPathLen': dtype('float64'), 'FID_': dtype('int32'), 'OBJECTID_1': dtype('int64'), 'OBJECTID_2': dtype('int64'), 'TAG': dtype('O'), 'Station': dtype('float64'), 'HydroID': dtype('int64'), 'STNAME': dtype('O'), 'Longitude': dtype('float64'), 'Latitude': dtype('float64'), 'Area_sqkm': dtype('float64'), 'SHORTNAME': dtype('O'), 'Elevation': dtype('float64'), 'Shape_Le_1': dtype('float64'), 'Shape_Le_2': dtype('float64'), 'Shape_Area': dtype('float64'), 'DArea': dtype('float64'), 'NodeID': dtype('float64'), 'SubCatID': dtype('float64'), 'geometry': <geopandas.array.GeometryDtype at 0x7f1472d25e80>}
Note that some of the input columns, LinkID, ToNodeID, FromNodeID, are integers, because of habits. It is preferable to have them as strings, but the converter will transparently convert them to string. Another thing is that there is a duplicated ID in the links:
gdf = link_specs
# Check for duplicates in the 'LinkID' column
duplicates = gdf["LinkID"][gdf["LinkID"].duplicated(keep=False)]
# Display the duplicated IDs
print(duplicates)
Series([], Name: LinkID, dtype: int64)
Let's see what happens:
link_specs = link_specs.drop(index=[3,17])
and now we expect the converter to do the job:
converter = ShapefileToSwiftConverter(
gdf = link_specs,
include_coordinates = True,
linkid_field = "LinkID",
fromnodeid_field = "FromNodeID",
tonodeid_field = "ToNodeID",
spathlen_field = "SPathLen",
darea2_field = "DArea",
geometry_field = "geometry",
)
result = converter.convert()
result
is a python dictionary
As expected given that some areas were negative in the input file (i.e. links without a contributing subarea), we have less subareas than links
f"there are {len(result['Links'])} links, {len(result['Nodes'])} nodes, {len(result['SubAreas'])} subareas"
'there are 119 links, 122 nodes, 76 subareas'
The object converter
has a save_to_file
method, or you can use the json
module to save the above result
:
import json
fp = Path.home() / "tmp" / "lachlan_swift.json"
with open(fp, "w") as f:
json.dump(result, f, indent=2)
Checking the json output loads as a catchment structure¶
This can be done if you have swift2
in your python env using the following.
See load_lachlan.ipynb.
# from swift2.model_definitions import model_from_json_file
# sim = model_from_json_file(fp)