Skip to content

CLI reference: lsdtt-hillslope-channel-coupling

Measures hillslopes against the channels they drain to. For every pixel on a drainage divide it records the hilltop curvature, traces the flow path down to the channel network, and reports the hillslope length and relief — together with the steepness of the channel that path reached.

The output is one row per hilltop pixel carrying the non-dimensional pair E* and R* of Roering et al. (2007), which is what lets a measured landscape be compared against nonlinear hillslope transport theory.

This is a port of the refactored path of lsdtt-hillslope-channel-coupling in LSDTopoTools2. The legacy alternatives (use_legacy_HFR, complete_hilltop_masking, the five HilltopFlowRouting* variants) are not ported.

For the streamline tracer underneath it see Flow routing; for the channel network that supplies the sinks see lsdtt-channel-extraction.

Usage

lsdtt-hillslope-channel-coupling <path> <parameter_file>
lsdtt-hillslope-channel-coupling <parameter_file>   # path defaults to ./
lsdtt-hillslope-channel-coupling -h                 # print help and exit
lsdtt-hillslope-channel-coupling -v                 # print version and exit

Parameter file format

# Lines beginning with # are comments.
key: value

Before you start: check the vertical units

Every quantity this tool reports scales linearly with elevation. If a DEM's elevations are in feet on a metre grid — the usual US state lidar delivery — then curvature, relief, gradient, E* and R* are all too large by 3.28, and nothing looks broken. The landscape merely appears steeper than it is. No raster format records a vertical unit, so no reader can detect this.

It is not a hypothetical. On a real 1 m dataset the error presented not as a bug but as a physical finding: three quarters of hilltops breached the hard bound R* < 1, which reads as evidence that the critical gradient S_c is wrong for the terrain. It is not — it is evidence that the elevations were in feet.

Establish the vertical unit before interpreting any R* population. Run the DEM through lsdtt-raster-preprocessing first: it warns when the median slope is physically implausible and, in US 3DEP coverage, queries USGS to settle metres against feet. This tool accepts vertical_units too, but the warning and the check live in preprocessing, because that is where a corrected raster gets written.


What the tool computes

Divides and hilltop pixels

A drainage divide runs between DEM pixels, not along them. lsdtt_ridgeline is an ordered sequence of pixel corners tracing that divide. The hilltop pixels are the DEM pixels the ridgeline separates — the ones immediately either side of it.

Each hilltop pixel therefore carries where it sits along its divide (ridgeline_id, ridgeline_node_index, distance_along_ridgeline_m) and which of the two opposing hillslopes it belongs to (ridge_side: 0 left of travel, 1 right).

basin_selection_choice: sibling is recommended: it makes an interfluve structural, since a divide's two flanking basins share a parent by construction.

Tracing

Each hilltop pixel is traced downslope by Lea (1992) aspect-driven kinematic routing with Tarboton (1997) edge handling, at sub-pixel resolution, until it reaches a channel cell. trace_surface_choice selects the raw DEM (default, so paths follow true topography) or the fitted polynomial surface.

The metrics

Lh   hillslope length   path length from hilltop to channel
R    relief             z_hilltop - z_channel
S    mean path gradient R / Lh
E*   = 2 |Cht| Lh / S_c
R*   = R / (Lh S_c)

R* < 1 is a hard bound of the framework, not a fitted quantity.

Cht is ALWAYS the Laplacian — this is not configurable

E* = 2|Cht|Lh/S_c is defined with the Laplacian ∇²z (Roering et al. 2007; Hurst et al. 2012), so that is what the tool uses. There is no parameter to change it.

A curvature_metric_choice parameter used to exist and defaulted to mean_curvature — lsdtt3's differential-geometry mean curvature,

H = ((1+q²)r − 2pqs + (1+p²)t) / (2(1+p²+q²)^{3/2})

which is a different quantity. It equals ∇²z/2 only where the gradient is zero; at finite gradient the metric terms make the ratio slope-dependent. Using it biased E* by about a factor of two, and biased gentle and steep hilltops by different amounts.

Nothing about the wrong answer looked wrong: R* stayed below 1, the cloud stayed tight, no warning was printed — the points simply sat in the wrong place on the curve. On a synthetic landscape with known forcing (U/D = 0.0080 m⁻¹), mean_curvature recovered 0.0035 (0.43×) and the Laplacian 0.0071 (0.89×). A parameter file that still sets the old key gets a note saying it was ignored.

Curvature sign

lsdtt3 uses the strict mathematical convention, so a convex-up hilltop has NEGATIVE curvature. E* uses |Cht|. A positive Cht is a concave pixel, which remove_positive_curvature_hilltops discards by default.

What Lh measures

Lh is the path length to where the trace enters the channel cell, not to the cell centre — short by up to half a diagonal. mean_path_gradient inherits a small high bias from this (~2 % on a synthetic test).


Trace outcomes

Every hilltop pixel gets a row, including the ones that were never traced. trace_status says what happened, and only status 0 has a meaningful Lh:

status meaning
0 reached a channel — the only rows with valid Lh, R, E*, R*
1 hit the edge of the DEM
2 loop detected — revisited a cell where it could still have descended: a genuine routing failure
3 no aspect at the source pixel
4 never offered to the tracer (sits on the DEM's outer ring)
5 stalled on flat — descended correctly, then ran out of descent with no channel to terminate on

Why 2 and 5 are different, and why it matters

They look like the same failure and are not.

A stall (5) is a statement about the channel network's coverage, not about the routing. The path is correct: it descends monotonically from ridge to valley floor and then oscillates on the flat because there is no channel cell there to stop it. On a real 1 m dataset such traces ended a median of 116 m from the nearest channel, while successful traces ended on one 100 % of the time. 74 % of what was formerly reported as looping was this.

A loop (2) is a genuine routing failure — the trace revisited a cell on ground it could still have descended. On the same dataset this was 1.8 % of hilltops within one hillslope length of a channel.

The split is decided by flat_terminus_gradient (default 0.02): the steepest descent available at the terminating cell.

A high stall count means extend the channel network, or read the Lh distribution as covering only the part of the DEM the network reaches. A high loop count means the Lh distribution is not reliable. The tool prints different advice for each.


Ingesting a channel network

channel_network_fname takes the output of lsdtt-channel-extraction directly (FlatGeobuf, GeoPackage or CSV), so both tools share exactly one definition of where the channels are. Channel heads are derived as channel cells with no channel donor.

This matters more than it looks: the channel head position is the single thing that sets hillslope length. A curvature-based detector (wiener) places it on evidence; threshold_contributing_pixels places it on a chosen number. Prefer the former, and ingest it rather than re-deriving it.

The network must come from the same DEM this tool reads. Points falling on nodata are dropped with a count; if all of them do, the run stops and says so.


Outputs

Line outputs follow write_vector_format; hilltop points may override it with hilltop_points_write_vector_format, which also accepts csv. Rasters follow write_output_format.

file contents
*_hilltop_points The main product. One point per hilltop pixel, with curvature, Lh, relief, E*, R*, trace_status, the ridgeline ordering, and the joined channel properties.
*_ridgelines The ordered divides.
*_hillslope_traces The traced flow paths, thinned by trace_thinning on write.
*_ridge_mask, *_Lh, *_channel_mask Optional rasters.
*_README.csv / .html Every parameter used, with its help text.

Undefined values are EMPTY

A blank field means undefined. It is never 0 and never -9999. A blank E_star means E* could not be computed, not that it is zero. Filter to trace_status == 0 before computing any distribution.

Channel properties joined to each hilltop

The channel a hilltop drains to is known from the trace, so its properties are attached in process: channel_k_sn, channel_chi, channel_elevation, channel_flow_distance_m, channel_drainage_area_m2, channel_basin_index, channel_segment_id. A post-hoc CSV join on floating-point coordinates would drop rows silently.

Rows whose channel pixel was not part of a fitted network keep an empty channel_k_sn — they are not zero and are not dropped.


Worked example

Southern Ohio, 1 m lidar, 5.33 km². Full write-up including the corrected DEM and the diagnostics in ../data/IndianCreek_1m/hillslope_channel_coupling_readme.md.

# 1. correct the DEM first (this one is in FEET, with nodata stored as zero)
lsdtt-raster-preprocessing ./ ft_to_m.param

# 2. channels, from curvature rather than an area threshold
lsdtt-channel-extraction ./ IC_wiener_final.param

# 3. couple
lsdtt-hillslope-channel-coupling ./ hcc_final.param

The settings that matter (the full file adds output-format switches and the optional rasters):

# hcc_final.param
read_path: ./
read_fname: indian_creek_metres.tif
write_path: ./
write_fname: IndianCreek_hcc

boundary_conditions: oooo
fill_before_routing: true

channel_network_fname: ./IndianCreek_channel_network_points.fgb

basin_selection_choice: sibling
min_basin_pixels: 500

ridge_extraction_algorithm_choice: ridgeline
stream_network_padding_pixels: 3
threshold_hilltop_gradient: 0.8
remove_positive_curvature_hilltops: true

surface_fitting_window_radius_metres: 6.0
critical_hillslope_slope: 0.8

run_chi_analysis: true
m_over_n: 0.45

hilltop_points_write_vector_format: flatgeobuf
write_ridgelines: true
write_hillslope_traces: true
trace_thinning: 50
write_output_format: gtiff
n_threads: 4

Result: 62,365 hilltop pixels, 55 % reaching a channel, median Lh 60 m, median R* 0.427, and 0.2 % breaching R* < 1 at S_c = 0.8.

Figures

lsdviztools3 renders the output set:

pixi run python -m lsdviztools3.cli.plot_hilltop_coupling \
    --prefix   ./IndianCreek_hcc \
    --dem      ./indian_creek_metres.tif \
    --channels ./IndianCreek_hcc_channel_mask.tif \
    --outdir   ./hillslope_coupling_figures

traces_on_hillshade, trace_outcomes, looped_trace_profiles, ridgelines_and_sides, length_distributions, ridgeline_profiles, estar_rstar.


Parameters

Generated from the tool's own help registry; lsdtt-hillslope-channel-coupling -h prints the same information.

Input

parameter type default what it does
boundary_conditions string nnnn Four-character N,E,S,W boundary code for the flow router.
fill_before_routing bool true Pit-fill the DEM before building the flow network.
min_elevation float -9999 Pixels at or below this elevation become nodata. The disabled sentinel preserves below-sea-level study areas; set 0 explicitly to remove sea or nodata-as-zero pixels.
vertical_units string metres Vertical unit of the input elevations: metres, feet or us_survey_feet.

Basin selection

parameter type default what it does
basin_selection_choice string sibling How basins are chosen; ridgelines come from their outlines.
min_basin_pixels int 100 Skip basins smaller than this.

Ridge extraction

parameter type default what it does
diagonal_step_policy string skip What to do with a non-4-connected step in a ridgeline.
divide_merge_search_steps int 5 Merge tolerance K for the divide_pairs fallback route.
remove_positive_curvature_hilltops bool true Drop hilltop pixels whose curvature is positive.
ridge_extraction_algorithm_choice string ridgeline How hilltop pixels are found.
stream_network_padding_pixels int 2 Drop hilltop pixels within this many pixels of a channel.
threshold_hilltop_gradient float 0.4 Drop hilltop pixels steeper than this. <= 0 disables.

Channel network

parameter type default what it does
channel_network_fname string `` Optional channel network to ingest instead of extracting one.
threshold_contributing_pixels int 1000 Contributing pixels defining a channel head.

Floodplain

parameter type default what it does
find_floodplain bool false Detect a floodplain with a simple gradient + HAND rule.
max_floodplain_gradient float 0.1 Gradient (m/m) above which ground is not floodplain. Replaces floodplain_gradient_threshold.
max_floodplain_hand_metres float 5.0 HAND (m) above which ground is not floodplain. Replaces floodplain_hand_threshold. The same names as in lsdtt-fluvial-surfaces.
floodplain_mask_fname string `` Optional binary floodplain raster to ingest.

Surface metrics

parameter type default what it does
surface_fitting_window_radius_metres float 0 Polynomial surface-fitting window radius in metres. 0 = 3 * cell size.

Tracing

parameter type default what it does
flat_terminus_gradient float 0.02 Gradient below which a trace that revisits a cell is reported as stalled_on_flat (5) rather than loop_detected (2).
hilltop_thinning int 1 Analyse every Nth hilltop pixel. 1 = all of them.
plan_curvature_threshold float 0.001 abs(plan curvature) above this counts a path cell as curved.
trace_max_steps int 100000 Hard cap on cell steps per trace.
trace_surface_choice string raw Which surface the flow paths are traced on: raw or fitted.
trace_thinning int 20 Write every Nth trace geometry. Affects the FILE only.

Chi

parameter type default what it does
chi_A0 float 1.0 Reference drainage area A0 for the chi integration (m²). Leave at 1.0 unless you know why: a chi-elevation gradient equals k_sn only when A0 = 1 m²; any other value silently rescales it by A0^(m/n). (Renamed from chi_A_0; the old key still works for one release, with a warning.)
chi_critical_divergence_metres float 5.0 Segment-fitting tolerance: max divergence (m) before a new segment.
m_over_n float 0.45 Concavity index m/n used for the chi integration.
run_chi_analysis bool false Fit the chi network and attach channel steepness to every hilltop row.

Non-dimensional

parameter type default what it does
critical_hillslope_slope float 0.8 Critical gradient S_c used to non-dimensionalise E* and R*.

Output

parameter type default what it does
write_vector_format string flatgeobuf Format for traced flow paths and ridgeline polylines.
hilltop_points_write_vector_format string same_as_write_vector_format Optional hilltop point-output override; also accepts csv.
write_channel_mask_raster bool false Write the channel mask actually used as sinks.
write_floodplain_mask_raster bool false Write the floodplain mask actually used.
write_hand_raster bool false Write the HAND raster used by the floodplain detector.
write_hillslope_length_raster bool false Write Lh at the hilltop pixels.
write_hillslope_traces bool false Write the traced flow paths as lines, thinned by trace_thinning.
write_hilltop_curvature_raster bool false Write Cht at the hilltop pixels.
write_hilltop_points bool true Write the hilltop table (one row per hilltop pixel).
write_output_format string cog Raster output format: cog, gtiff or png.
write_relief_raster bool false Write hillslope relief at the hilltop pixels.
write_ridge_mask_raster bool false Optional coupling diagnostic: hilltop pixels coded by side. Unlike feature-finder's primary mask output, it is off by default.
write_ridgelines bool false Write the ordered ridgelines as lines.

Performance

parameter type default what it does
n_threads int 0 Thread count. 0 = hardware default.

References

Lea, N.L. (1992), An aspect-driven kinematic routing algorithm, in Overland Flow: Hydraulics and Erosion Mechanics.

Roering, J.J., Perron, J.T. and Kirchner, J.W. (2007), Functional relationships between denudation rate and hilltop curvature. EPSL 264:245-258.

Tarboton, D.G. (1997), A new method for the determination of flow directions and upslope areas in grid digital elevation models. Water Resources Research 33:309-319.

Hurst, M.D., Mudd, S.M., Walcott, R., Attal, M. and Yoo, K. (2012), Using hilltop curvature to derive the spatial distribution of erosion rates. JGR Earth Surface 117:F02017.

Parameters

This section is generated from the executable's -h json registry. Do not edit it manually.

Status: experimental. This CLI is not yet fully tested.

File I/O

Parameter Type Default Role Parent Description Guidance
read_path string ./ io - Directory from which input files are read. Defaults to the directory holding the parameter file.
read_fname string - io - Input filename, with or without extension (e.g. my_dem.tif). Read from read_path. lsdtt3 uses GDAL, so any GDAL-readable raster format works. If empty, defaults to the parameter filename stem.
write_path string - io - Directory to which output files are written. Defaults to read_path when not set.
write_fname string - io - Output filename prefix (no path, no extension). All outputs are named <write_fname>_<descriptor>.<ext>. Defaults to the stem of read_fname when not set.

Input

Parameter Type Default Role Parent Description Guidance
boundary_conditions string nnnn param - Four-character N,E,S,W boundary code for the flow router. 'n' no flux, 'p' periodic, 'o'/'b' open or base level. MUST match how the DEM was made: a grid with no draining edge makes the router throw. Note 'o' and 'b' are inconsistent between the router and the hillslope solvers, so divides within one hillslope length of such an edge are not trustworthy.
vertical_units string metres param - Vertical unit of the input elevations: metres, feet or us_survey_feet. NO raster format records the vertical unit, so this CANNOT be detected and is NEVER applied automatically. Much US state lidar is NAVD88 FEET on a metre grid; left uncorrected, hilltop curvature, relief, E* and R* are all wrong by 3.28 and NOTHING downstream looks broken - the landscape merely appears far steeper than it is. Establish the vertical datum from the data provider before setting this.
min_elevation float -9999 param - Cells at or below this elevation (m) become nodata before any analysis. -9999 disables. For removing the sea, which many DEMs store as valid cells at about 0 m, and nodata stored as 0 (a block of zeros beside real terrain is a cliff that captures flow paths). Removed cells that touch the DEM edge act as an open boundary, so a river reaching the coast drains off the DEM there. Negative values apply as given: where land lies below sea level (fens, polders, Death Valley -86 m, the Dead Sea -430 m) set it just below the lowest land, or below the sea surface of the DEM, so that flow is still routed over the sub-zero land. -9999 (or lower) disables.

Pit filling

Parameter Type Default Role Parent Description Guidance
fill_before_routing bool true switch - Choose whether to pit-fill the DEM before building the flow network. ASKS: should the DEM be filled at all? Filling is OPTIONAL here and this is a genuine analytical choice. True (the default) routes over a pit-free surface. False builds the flow network on the UNFILLED surface, so flow paths terminate at sinks instead of being carried through them. Do not confuse this with raster_is_filled, which is an assertion that the input is already filled.

Channel network

Parameter Type Default Role Parent Description Guidance
threshold_contributing_pixels int 1000 param - Contributing-pixel threshold defining a channel head. The total number of upslope contributing pixels from the flow-routing object, not the number of direct donors to a pixel. Reduce this value to extract a denser network. This is a PIXEL COUNT and therefore depends on the grid resolution: the equivalent drainage area is threshold_contributing_pixels x cell area. Where a genuine area is wanted instead, the convention is <what>_area_threshold_m2.
channel_network_fname string - param - Optional channel network to ingest instead of extracting one. A point file written by lsdtt-channel-extraction (write_channel_network_points), carrying row, col, flat and stream_order. It MUST have been extracted on this DEM's grid: 'flat' is row-major on those dimensions and a mismatch is rejected.

Basin selection

Parameter Type Default Role Parent Description Guidance
basin_selection_choice string sibling param - How basins are chosen; ridgelines come from their outlines. sibling: every junction with two or more donors becomes a parent and its donor sub-basins are the selection. This makes an interfluve STRUCTURAL -- a divide's two flanking basins share a parent by construction -- and is the recommended choice for hilltop work. all_junctions: one basin per junction; network-wide but deeply nested, so divides are traced many times and must be deduplicated.
min_basin_pixels int 100 param - Skip basins smaller than this. Tiny basins produce degenerate outlines and no usable hillslopes.

Ridge extraction

Parameter Type Default Role Parent Description Guidance
ridge_extraction_algorithm_choice string ridgeline param - How hilltop pixels are found. ridgeline: hilltop pixels are the DEM pixels that an ORDERED ridgeline separates, so each one carries its position along the divide and which side it is on. divide_pairs: a flow-path merge test over the whole DEM that needs no basins, but yields no ordering and no divide identity. Use it as a fallback when basin outlines are slow or fragile.
diagonal_step_policy string skip param - What to do with a non-4-connected step in a ridgeline. A diagonal corner-to-corner step lies along no lattice edge, so it separates no well-defined pixel pair. skip / bridge / fail. Measured on real basin outlines: 1808 of 1808 edges were cardinal, so this is a safety net rather than a routine path.
divide_merge_search_steps int 5 param - Merge tolerance K for the divide_pairs fallback route. Two adjacent pixels are a divide pair if their flow paths do not meet within K steps. Ignored unless ridge_extraction_algorithm_choice is divide_pairs.
stream_network_padding_pixels int 2 param - Drop hilltop pixels within this many pixels of a channel. NOT optional in practice. A basin outline includes the segments running beside the channel down to the outlet, so an unfiltered ridge set contains pixels sitting ON the channel with no hillslope at all -- measured at 39 percent on a test fixture. 0 disables; 1 drops only pixels that are themselves channel pixels.
threshold_hilltop_gradient float 0.4 param - Drop hilltop pixels steeper than this. <= 0 disables. Steep 'ridges' are usually landslide scarps or DEM noise.
remove_positive_curvature_hilltops bool true param - Drop hilltop pixels whose curvature is positive. A hilltop is convex, and under lsdtt3's sign convention a convex-up ridge has NEGATIVE curvature. A positive value is therefore not a hilltop. Note this is the opposite sign to some other packages.

Surface metrics

Parameter Type Default Role Parent Description Guidance
surface_fitting_window_radius_metres float 0 param - Polynomial surface-fitting window radius in metres. 0 = 3 * cell size. Cht is SCALE DEPENDENT, so this is a scientific parameter, not a smoothing detail. It is written into the output summary because an E* quoted without its window is not reproducible.

Floodplain

Parameter Type Default Role Parent Description Guidance
floodplain_mask_fname string - param - Optional binary floodplain raster to ingest. It does TWO things, and both matter: floodplain pixels are added to the SINK set, so a trace entering the valley floor terminates there, AND removed from the ridge set, so a floodplain-interior 'hilltop' cannot produce a degenerate zero-length row.
find_floodplain bool false switch - Detect a floodplain with a simple gradient + HAND rule. floodplain = gradient < threshold AND HAND < threshold, hole-filled. This is a CONVENIENCE, not a classifier: it has no reach-relative banding and no terrace separation, so it will swallow terraces and plateaus. Use lsdtt-fluvial-surfaces for real work. Default off so the tool's behaviour never silently depends on two arbitrary numbers. HAND is height above nearest drainage (Nobre et al. 2011, J. Hydrology 404:13-29).
max_floodplain_gradient float 0.1 param find_floodplain Gradient (m/m) above which ground is not floodplain. A gradient, not an angle (gradient = tan(angle)). Used only when find_floodplain is true. Replaces floodplain_gradient_threshold.
max_floodplain_hand_metres float 5 param find_floodplain HAND (m) above which ground is not floodplain. HAND is height above nearest drainage (Nobre et al. 2011, J. Hydrology 404:13-29), measured along the flow path to the channel. Used only when find_floodplain is true. Replaces floodplain_hand_threshold.
floodplain_threshold_algorithm_choice string fixed param find_floodplain How the floodplain bounds are chosen: fixed, qq_gaussian or cdf_divergence. fixed uses max_floodplain_hand_metres and max_floodplain_gradient as given. qq_gaussian is Clubb et al. (2017): for each quantity, the lowest value at which the data rejoin a Gaussian drawn through two percentiles of the quantile-quantile plot (floodplain_qq_*), and stay on it. cdf_divergence fits a family of distributions and takes the value at which the empirical CDF most exceeds the best fit. The chosen values are printed and written to the ingested-parameters file, so a run can be repeated with fixed.

Threshold selection

Parameter Type Default Role Parent Description Guidance
floodplain_qq_lower_percentile float 25 param floodplain_threshold_algorithm_choice Lower percentile of the QQ cloud the Gaussian reference line is drawn through (qq_gaussian). 25 and 75 (the IQR) are the values Clubb et al. (2017) used.
floodplain_qq_upper_percentile float 75 param floodplain_threshold_algorithm_choice Upper percentile of the QQ cloud the Gaussian reference line is drawn through (qq_gaussian). Must be above the lower percentile.
floodplain_qq_threshold_fraction float 0.01 param floodplain_threshold_algorithm_choice Fraction of the data range within which a quantile counts as on the Gaussian line (qq_gaussian). 0.01 (1%) is the paper's value. The threshold is the lowest quantile that is on the line and stays on it for the next 200 quantiles of 10000. Larger values admit more ground.

Tracing

Parameter Type Default Role Parent Description Guidance
trace_surface_choice string raw param - Which surface the flow paths are traced on: raw or fitted. raw (default): the unmodified DEM, so paths follow true topography. That is the right choice in principle, but on high-resolution lidar micro-topography makes the Tarboton edge-routing branch cycle, and a trace that cycles yields no hillslope length at all -- measured at 48 percent of traces on a 1 m dataset. fitted: the polynomial fitted surface at surface_fitting_window_radius_metres, which is the SAME surface the curvature is measured on, so aspect and Cht become mutually consistent. It CHANGES WHAT Lh MEANS -- shorter, smoother paths -- so it is a declared choice and is reported in the run header, never applied silently.
hilltop_thinning int 1 param - Analyse every Nth hilltop pixel. 1 = all of them. This THINS THE ANALYSIS and therefore changes every distribution in the output table. It is not a rendering option -- for that use trace_thinning. Leave at 1 unless you know why you are subsampling.
trace_thinning int 20 param write_hillslope_traces Write every Nth trace geometry. Affects the FILE only. Full-resolution trace geometry on a large DEM is millions of LineStrings and tens of gigabytes, and no viewer will draw it. The hilltop table always comes from every analysed pixel regardless of this setting.
trace_max_steps int 100000 param - Hard cap on cell steps per trace. Stops a runaway trace on flat or noisy topography.
flat_terminus_gradient float 0.02 param - Gradient below which a trace that revisits a cell is reported as stalled_on_flat (5) rather than loop_detected (2). These are different failures and want different responses. A stall means the path descended CORRECTLY and then found no channel to terminate on - a statement about the channel network's coverage, not about the routing; extend the network, or read Lh as covering only the part of the DEM the network reaches. A loop means the trace revisited a cell on ground it could still have descended, which is a genuine routing failure and makes Lh unreliable. Measured as the steepest descent to any of the eight neighbours at the terminating cell. The default is below any hillslope and above the residual gradient a fill leaves on a flat; it is calibrated on one 1 m landscape, where 74% of reported loops turned out to be stalls.
plan_curvature_threshold float 0.001 param - abs(plan curvature) above this counts a path cell as curved. Drives divergent_count and planar_count, which together sum to the number of visited cells. Note 'divergent' counts CURVED cells of either sign, because the test is on the magnitude.

Chi

Parameter Type Default Role Parent Description Guidance
run_chi_analysis bool false switch - Fit the chi network and attach channel steepness to every hilltop row. This is the COUPLING the tool is named for: hillslope form (Cht, Lh, E, R) alongside the k_sn of the channel that hillslope actually drains to. k_sn is fitted per SEGMENT, so each channel node is matched to the segment whose chi interval contains it. Off by default because the fit costs real time and is not needed for the hillslope metrics alone.
m_over_n float 0.45 param run_chi_analysis Concavity index m/n used for the chi integration. Chi is only comparable between basins computed with the SAME m/n, so this value is written into the summary.
chi_A0 float 1.0 param run_chi_analysis Reference drainage area A0 for the chi integration (m2). LEAVE THIS AT 1.0 UNLESS YOU KNOW WHY YOU ARE CHANGING IT. The slope of a chi-elevation profile equals the channel steepness index k_sn ONLY when A0 = 1 m2; for any other A0 the gradient is k_sn scaled by A0^(m/n). The rescaling is silent and large - A0 = 1e6 m2 at m/n = 0.45 scales every gradient by about 631. Other packages default differently (TopoToolbox's chitransform uses a0 = 1e6), so state A0 explicitly whenever a value is compared across tools.
chi_critical_divergence_metres float 5.0 param run_chi_analysis Segment-fitting tolerance: max divergence (m) before a new segment. Larger values give fewer, longer segments and therefore smoother k_sn.

Non-dimensional

Parameter Type Default Role Parent Description Guidance
critical_hillslope_slope float 0.8 param - Critical gradient S_c used to non-dimensionalise E* and R*. E* = 2|Cht|Lh/S_c and R* = R/(Lh S_c), so both are only as meaningful as this number and the tool cannot check it for you. 0.8 reproduces the value hard-coded in the legacy tool, which is the value to use for any comparison against legacy output.

Output

Parameter Type Default Role Parent Description Guidance
hilltop_points_write_vector_format string same_as_write_vector_format io - Format for the hilltop point output. flatgeobuf (or fgb), gpkg, or csv. FlatGeobuf is the default and is recommended: GeoPackage is unreliable on mounted filesystems such as WSL2's /mnt/c.
write_vector_format string flatgeobuf io - Vector output format: flatgeobuf or gpkg. Governs every vector layer this tool writes. FlatGeobuf is preferred: it is compact, carries its own georeferencing, and does not have GeoPackage's problems writing across drives (a common WSL2 situation). CSV is available only through selectors for point/table outputs. Per-output overrides exist only where a container genuinely differs. Raster outputs are governed separately by write_output_format.
write_output_format string cog io - Raster output format: cog, gtiff or png. Shared by every raster this tool writes.
write_hilltop_points bool true switch - Write the hilltop table (one row per hilltop pixel). The main product.
write_hillslope_traces bool false switch - Write the traced flow paths as lines, thinned by trace_thinning. Off by default because the geometry is large and is a diagnostic rather than a result.
write_ridgelines bool false switch - Write the ordered ridgelines as lines. Cheap, and it is what makes ridgeline_id and distance_along_ridgeline_m on the points usable -- without the lines those columns reference something the user cannot see.
write_ridge_mask_raster bool false switch - Write a raster of the hilltop pixels, coded by side. This is an optional diagnostic in the coupling workflow, so it is off by default; the feature-finder mask with the same key is a primary output. 0 not a hilltop, 1 left of travel, 2 right of travel.
write_hilltop_curvature_raster bool false switch - Write Cht at the hilltop pixels. -
write_hillslope_length_raster bool false switch - Write Lh at the hilltop pixels. -
write_relief_raster bool false switch - Write hillslope relief at the hilltop pixels. -
write_hand_raster bool false switch find_floodplain Write the HAND raster used by the floodplain detector. Only produced when find_floodplain is true.
write_channel_mask_raster bool false switch - Write the channel mask actually used as sinks. Worth having when the network was INGESTED: it is the only way to see what was really used, as opposed to what the file was supposed to contain.
write_floodplain_mask_raster bool false switch - Write the floodplain mask actually used. Whether ingested or detected.

Performance

Parameter Type Default Role Parent Description Guidance
n_threads int 0 param - Thread count. 0 = hardware default. Measured scaling on this workload saturates near 2x on four physical cores; hyperthreads add nothing.

Interior nodata

Parameter Type Default Role Parent Description Guidance
interior_nodata_method string sink param - How nodata pixels inside the DEM are treated: sink or fill. Interior nodata are nodata pixels not connected to the raster edge through other nodata (isolated voids, moulins, masked lakes). sink (the default, unchanged behaviour): they are outlets, so flow that reaches them ends there, as at the DEM edge; use this for real internal drainage (e.g. moulins on an ice sheet). fill: they are interpolated with nodata_fill_method_choice before any filling or routing, so flow passes across them; use this for data voids. Nodata connected to the edge (e.g. sea removed by min_elevation) is never filled and always acts as an open boundary.
nodata_fill_method_choice string laplacian param interior_nodata_method=fill Method for filling interior nodata pixels. laplacian: smooth Dirichlet interpolation (recommended). iterative_weighted_average: fast, well-suited to thin voids. Used when interior_nodata_method is fill.
nodata_fill_max_iter int 10000 param interior_nodata_method=fill Maximum iterations for iterative nodata fill methods. Used when interior_nodata_method is fill.