Skip to content

Tool · Python · MIT

FlowMorph

Version 1.0released

Version 1.0 is the current release: the Python package on GitHub under the MIT licence, the Python version of the C code of FlowMorph 1.0. The FullBasin v1.0 layers were made with the older FlowMorph 0.1.

The shape and terrain of every pixel's upstream catchment. For every pixel whose upstream drainage area is at least 10 km², FlowMorph computes sixteen attributes of the catchment that drains to it: six upstream aggregates of elevation and slope, taken in one pass over the flow tree; four planform metrics traced from the catchment boundary; and six arithmetic derivatives. By use they regroup into eight terrain statistics and eight basin-shape metrics.

Tested on

Tested on MERIT Hydro at 3 arc-seconds, on three regions of the global partition (5699, 20507 and 20106; the largest has 10.7 million pixels, 178,129 of them with 10 km² or more upstream): the seventeen layers equal those of the C code bit for bit, with the slope's ring read from the global elevation.

The sixteen attributes

The eight terrain statistics on the example basin of the FullBasin paper
The eight terrain statistics on the example basin of the FullBasin paper (basin 8595, southeastern Fujian, China; 729 km², 3 arc-seconds): (a) elevation, for context; (b)–(g) the six upstream aggregates; (h) basin relief and (i) the hypsometric integral. Each pixel with at least 10 km² upstream is drawn as a circle whose radius grows with log10 of its upstream area; the black line is the basin boundary and ▼ the outlet. Figure 8 of the FullBasin paper.
The eight basin-shape metrics on the same basin
The eight basin-shape metrics on the same basin: (a) upstream drainage area, for context; (b)–(e) the four planform metrics; (f)–(i) the four shape indices. Figure 9 of the FullBasin paper, made with FlowMorph 0.1. In version 1.0 the convexity (e) takes the convex hull of the pixels, not of their centres, and lemniscate_ratio is Chorley's ratio of perimeters; panel (i) shows the parameter k = π L² / (4A) that 0.1 wrote under that name.
#layervariableunitgroup
1mean_elvmean upstream elevationmupstream aggregate
2min_elvminimum upstream elevationmupstream aggregate
3max_elvmaximum upstream elevationmupstream aggregate
4elv_stdupstream elevation standard deviationmupstream aggregate
5mean_slpmean upstream slopedegupstream aggregate
6slp_stdupstream slope standard deviationdegupstream aggregate
7perimeter_kmcatchment perimeterkmboundary walk
8basin_length_kmbasin lengthkmboundary walk
9basin_width_kmbasin widthkmboundary walk
10convexityconvexity–boundary walk
11reliefbasin reliefmarithmetic
12hypsometric_integralhypsometric integral–arithmetic
13elongation_ratioelongation ratio–arithmetic
14graveliusGravelius compactness–arithmetic
15circularitycircularity ratio–arithmetic
16lemniscate_ratiolemniscate ratio–arithmetic

Written where the upstream area is at least 10 km², −9999 elsewhere; the local slope slp is written as well. The definitions are in the README on GitHub.

How it works

The pixels of each basin are numbered depth first from the outlet (FlowTopo's seq_dfs), so the catchment of a pixel is one run of ranks and "is q upstream of p" is two comparisons. The terrain aggregates take one pass over the ranks. The boundary is walked once for a run of pixels along a stream, and carried from one catchment to the next: only the pixels new to the catchment are tested.

The boundary walk on the example basin of the FullBasin paper
The boundary walk on the example basin. (a) For a target T₁ on the main stem, the boundary of its catchment: the part on the basin perimeter (grey) and the closing edge inside the basin (red). (b) Moving the target downstream to T₂, the new boundary follows from the old one: pixels kept (grey), deleted (red) and added (green). (c), (d) How the streams of the basin, and three parts of the main stem, were shared among threads for the FullBasin run; the Python package walks them one after another. Figure 7 of the FullBasin paper.

Get it

Python 3.10 or later with numpy, numba, scipy and rasterio.

git clone https://github.com/hellolulujiang/flowmorph.git
cd flowmorph
pip install -e ".[test]"
pytest
import flowmorph

fm = flowmorph.FlowMorph.from_raster("data/dir_example.tif", "data/upa_example.tif", "data/elv_example.tif")
attributes = fm.attributes()          # name -> float32 grid, -9999 where not written
fm.write("out")                       # seventeen GeoTIFFs: slp and the sixteen attributes

The bundled example is one basin of MERIT Hydro in Tasmania (696 km², 110,125 pixels, 2,033 of them with 10 km² or more upstream).

Licence

MIT for the code; see the licence. The bundled MERIT Hydro excerpt keeps its own terms, and the three figures above are Figures 7, 8 and 9 of the FullBasin paper (Earth System Science Data Discussions, CC BY 4.0). Author: Lulu Jiang (lulujiang.me).

Site under development — pages may change daily. Comments and corrections are welcome: [email protected]