Skip to content

CLI reference: lsdtt-feature-finder

Experimental detectors for small linear and areal features on high-resolution (lidar) DEMs: drains, channel candidates, valleys, roads and tracks. Each run does one feature_type. The tool is experimental and many of the detectors are not selective on real terrain; treat their outputs as candidates to check, not as a classification.

Usage

lsdtt-feature-finder  <path> <parameter_file>
lsdtt-feature-finder  <parameter_file>        # path defaults to ./
lsdtt-feature-finder  -h                      # print help and exit
lsdtt-feature-finder  -v                      # print version and exit
lsdtt-feature-finder  -c                      # print citation and exit

Parameter file format

# Lines beginning with # are comments.
key: value

Keys use snake_case. All keys and their defaults are listed under Parameters below.


Feature types

Set feature_type to one of these (default channel_candidates). The parameters for each are in the matching group under Parameters.

feature_type What it does Parameter group
channel_candidates Multiscale curvature persistence combined with Hessian elongation; a channel-candidate score in [0, 1] and a mask Hessian elongation filter
find_drains Frangi ridge/valley filter for narrow drainage ditches, then shape filtering Drain finder
relief_ratio Local relief at a short radius divided by local relief at a long radius Relief-ratio detector
relative_path_impact Relative Path Impact Index (Tarolli et al. 2013), D8 version: drainage area on the original versus a smoothed DEM Relative Path Impact Index
local_median_relative_elevation Elevation relative to a local median, with drain, top, bottom and transition masks Local median + relative elevation
find_valleys SMAP surface-shape classes on a smoothed DEM; the concave-up classes form the valley mask Valley finder
find_roads Along-contour benches: Hessian elongation × contour alignment, gated by slope and curvature Road finder
flow_road_discrimination Separates flow pathways from roads by comparing D8 flow bearing with the regional slope bearing Flow-pathway road/channel discrimination
path_opening Grayscale path opening: keeps long, continuous bright threads and removes speckle Path opening
structure_tensor Structure-tensor coherence (line-likeness) and orientation Structure-tensor coherence
diffusion Coherence-enhancing diffusion Coherence-enhancing diffusion
ridge_lines Oriented non-maximum suppression with hysteresis linking: one-pixel ridge centrelines Ridge lines
track_spacing Local directional periodicity: the dominant spacing (m) of repeated linear features Track spacing
extract_roads Composed road extractor (diffusion, coherence, ridge thinning, clean-up) Road extractor
extract_roads_smooth Roads as smooth, low-roughness ribbons Smoothness road extractor
roughness Roughness (standard deviation, or 1 − R for circular data such as an orientation raster) of an input raster Generic roughness / consistency
thin_lines Separates thin lines from blobs and speckle Thin-line extractor
find_risers Short steep steps between gentler surfaces (terrace risers, shorelines, scarps) as open line segments, each with a step height and face gradient; optional A* gap closing Riser finder (find_risers)

flow_road_discrimination builds a D8 channel network from threshold_contributing_pixels (default 1000). big_channel_threshold_contributing_pixels (default 5000) selects the larger channels exported as valley-channel points. The former flow_big_channel_threshold_pixels spelling remains an unchanged-value alias.

Outputs

Every output has its own write_* switch, listed with its file name in the parameter tables below. All rasters are named <write_fname>_<descriptor>.<ext>, with the extension set by write_output_format (default cog). flow_road_discrimination also writes two FlatGeobuf point layers, <write_fname>_flow_divergent_points.fgb and <write_fname>_flow_valley_channel_points.fgb.

Orientation outputs (_orientation_deg, _spacing_orientation_deg) are azimuths of the feature's direction in [0, 180), clockwise from north.

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.

General

Parameter Type Default Role Parent Description Guidance
feature_type string channel_candidates param - Feature mode to run. Supported values: channel_candidates, find_drains, relief_ratio, relative_path_impact, local_median_relative_elevation, find_valleys, find_roads, flow_road_discrimination, path_opening, structure_tensor, diffusion, ridge_lines, track_spacing, extract_roads, extract_roads_smooth, roughness, thin_lines, find_risers.
n_threads int 0 io - Number of OpenMP threads. 0 = use all hardware threads. Applies to wavelet fitting and polyfit metric computation.
write_output_format string cog io - Output raster format. Allowed values: cog, gtiff, same_as_input, png. cog: Cloud Optimised GeoTIFF (default). gtiff: plain compressed GeoTIFF. same_as_input: match the input raster format. png: 8-bit scaled image with a worldfile and PAM sidecar for georeferencing - for quick visualisation only, not for analysis reuse. Output files take the extension of the chosen format.
channel_lambda_min_metres float 3.0 param - Minimum wavelength for multiscale channel-candidate curvature analysis, in metres. Use a value near the narrowest expected natural channel width or bottom width.
channel_lambda_max_metres float 18.0 param - Maximum wavelength for multiscale channel-candidate curvature analysis, in metres. Use a broader value that captures larger natural channel forms.
channel_n_scales int 5 param - Number of scales used in the multiscale channel-candidate detector. Scales are log-spaced between channel_lambda_min_metres and channel_lambda_max_metres.
polyfit_curvature_metric string plan_curvature param - Polyfit curvature metric used for channel-candidate detection. Suggested starting values: plan_curvature or tangential_curvature.
polyfit_curvature_sign string positive param - Whether channel-like pixels correspond to positive or negative curvature. Allowed values: positive (default), negative. Positive curvature = concave = convergent (channel); negative curvature = convex = divergent (ridge).
polyfit_method string direct param - Polyfit algorithm: direct (rolling-moment, O(n), default) or wavelet (FFT-based). direct is faster and better at resolving fine-scale features and is the recommended choice.
polyfit_z_factor float 1.0 param - Vertical scaling applied before interpreting polyfit derivatives. Usually leave at 1.0 unless experimenting.
polyfit_flat_slope_tolerance float 1e-12 param - Flat-slope tolerance passed to the polyfit metric engine. Very small default.
channel_depth_window_radius_metres float 12.0 param - Radius of moving-window mean used to derive local depth support, in metres. Depth signal is positive_part(local_mean - dem).
depth_window_shape string circular param - Shape of moving window used for local depth support. Allowed values: square, circular.
channel_weight_persistent float 0.7 param - Weight for multiscale curvature persistence in the final score. Usually the dominant term.
channel_weight_depth float 0.3 param - Weight for local depth support in the final score. Helps favour locally low pixels.
channel_weight_slope float 0.0 param - Optional slope weight in the final score. Recommended to keep small or zero at first.
channel_score_threshold float 0.5 param - Threshold applied to final channel-candidate score to make a binary mask. Lower is more inclusive.
write_channel_candidate_score_raster bool true switch - Write final channel-candidate score raster. Continuous score in [0,1].
write_channel_candidate_mask_raster bool true switch - Write thresholded binary channel-candidate mask. 1 indicates plausible channel candidate.
write_channel_best_scale_raster bool true switch - Write best persistent scale raster for channel candidates. Useful later for cross-road matching.
write_channel_candidate_diagnostic_rasters bool true switch - Write intermediate diagnostic rasters for the channel-candidate detector. Includes persistent response, depth signal, slope signal, and Hessian elongation.
write_channel_scale_diagnostic_rasters bool false switch - Write per-scale diagnostic rasters (verbose). Includes raw curvature, normalised channelness signal, and pairwise persistence for every scale. Disabled by default to reduce output volume.

Hessian elongation filter

Parameter Type Default Role Parent Description Guidance
use_hessian_filter bool true switch - Apply a Hessian eigenanalysis filter to retain only line-like features. Pixels where the dominant curvature eigenvalue does not substantially exceed the cross-track eigenvalue are removed from the mask.
hessian_elongation_threshold float 0.6 param use_hessian_filter Minimum Hessian elongation to retain in the channel mask. elongation = |lambda_major| / (|lambda_major| + |lambda_minor|). 0.5 is vacuous (always true); 0.6 removes near-isotropic pits/peaks; higher values are more selective.

Relief-ratio detector

Parameter Type Default Role Parent Description Guidance
write_relief_ratio_raster bool true switch - Write the relief-ratio raster. The output is local_relief(short_radius) / local_relief(long_radius), using circular moving windows.
relief_ratio_short_radius_metres float 1.8 param write_relief_ratio_raster Short moving-window radius for local relief, in metres. Use a radius matched to the narrow drain scale. This is a radius, not a diameter.
relief_ratio_long_radius_metres float 8.0 param write_relief_ratio_raster Long moving-window radius for local relief, in metres. Use a broader radius that captures channel-scale topographic relief.

Relative Path Impact Index (Tarolli-style, D8 adaptation)

Parameter Type Default Role Parent Description Guidance
rpii_polyfit_lambda_metres float 30.0 param - Surface-fitting window (lambda, metres) for the smoothed reference DEM. Computed using direct polyfit fitted_surface.
rpii_fill_min_slope float 0.0001 param - Minimum slope used when pit-filling original and smoothed DEMs. Passed to fill_pits() before D8 routing.
rpii_boundary_conditions string oooo param - Boundary conditions for D8 routing (N,E,S,W). o=open, n=no-flux.
rpii_flow_routing_method string d8 param - Flow routing method for drainage-area rasters in RPII. Allowed values: d8, dinf (d-infinity).
rpii_max_steps int 400 param - Legacy parameter retained for backwards compatibility. Not used by the current algebraic RPII definition.
write_rpii_raster bool true switch - Write Relative Path Impact Index raster. After Tarolli et al. (2013, https://doi.org/10.5721/EuJRS20134610): RPII = ln((A_r - A_sm) / A_sm), where A_r is drainage area on the filled original DEM and A_sm is drainage area on the filled smoothed DEM. Output: <write_fname>_relative_path_impact_index.<ext>.
write_rpii_log10_area_raw_raster bool true switch - Write log10(A_r) where A_r is drainage area on the filled original DEM. Output: <write_fname>_rpii_log10_area_raw.<ext>.
write_rpii_log10_area_smoothed_raster bool true switch - Write log10(A_sm) where A_sm is drainage area on the filled smoothed DEM. Output: <write_fname>_rpii_log10_area_smoothed.<ext>.
write_rpii_smoothed_surface_raster bool false switch - Write the surface-fitted DEM used by RPI. Output: <write_fname>_rpii_smoothed_surface.<ext>.

Local median + relative elevation

Parameter Type Default Role Parent Description Guidance
local_median_window_radius_metres float 6.0 param - Circular moving-window radius for local median, in metres. Increase to compare each pixel against broader neighbourhood context.
write_local_median_raster bool true switch - Write local median elevation raster. Output: <write_fname>_local_median.<ext>.
write_local_median_relative_elevation_raster bool true switch - Write relative elevation with respect to local median. relative = dem - local_median. Negative = below local median; positive = above local median. Output: <write_fname>_local_median_relative_elevation.<ext>.
local_median_drain_negative_threshold_metres float 0.15 param - Magnitude threshold (m) for drain-candidate trough pixels. Drain candidate mask keeps pixels where relative_elevation <= -threshold.
local_median_top_positive_threshold_metres float 0.15 param - Positive threshold (m) for top-surface candidate pixels. Top mask keeps pixels where relative_elevation >= threshold.
local_median_bottom_negative_threshold_metres float 0.15 param - Magnitude threshold (m) for bottom-surface candidate pixels. Bottom mask keeps pixels where relative_elevation <= -threshold.
local_median_hag_intermix_radius_metres float 2.0 param - Radius (m) for local top/bottom intermix detection. A pixel is intermix where both top and bottom masks are present within this circular neighbourhood.
local_median_hag_gradient_threshold float 0.25 param - Gradient threshold on relative elevation for hag-transition candidates. Transition mask keeps intermix pixels where gradient magnitude >= this value.
write_local_median_gradient_raster bool true switch - Write gradient magnitude of local-median relative elevation. Output: <write_fname>_local_median_relative_elevation_gradient.<ext>.
write_local_median_drain_candidate_mask_raster bool true switch - Write binary drain-candidate mask from negative relative elevation. Output: <write_fname>_local_median_drain_candidate_mask.<ext>.
write_local_median_top_mask_raster bool true switch - Write binary top-surface candidate mask. Output: <write_fname>_local_median_top_mask.<ext>.
write_local_median_bottom_mask_raster bool true switch - Write binary bottom-surface candidate mask. Output: <write_fname>_local_median_bottom_mask.<ext>.
write_local_median_hag_intermix_mask_raster bool true switch - Write binary top/bottom intermix mask. Output: <write_fname>_local_median_hag_intermix_mask.<ext>.
write_local_median_hag_transition_mask_raster bool true switch - Write binary hag-transition candidate mask (intermix + high gradient). Output: <write_fname>_local_median_hag_transition_mask.<ext>.

Drain finder

Parameter Type Default Role Parent Description Guidance
frangi_sigma_min_metres float 1.0 param - Minimum Frangi Gaussian scale in metres. Use small values for narrow drain bottoms in high-resolution DEMs.
frangi_sigma_max_metres float 2.5 param - Maximum Frangi Gaussian scale in metres. Set this near the expected width of the drain-bottom signal rather than the spacing between drains.
frangi_n_scales int 4 param - Number of Frangi scales. Scales are sampled logarithmically between the minimum and maximum Frangi sigma values.
frangi_beta float 0.4 param - Frangi beta parameter. Lower values more strongly prefer line-like over blob-like responses.
frangi_c float 1.0 param - Frangi c parameter. Controls suppression of weak-structure responses. Smaller values make the filter respond more selectively to subtle narrow drains.
drain_max_frangi_scale_metres float 1.8 param - Maximum allowed Frangi best scale, in metres, for retained drain candidates. Use this to suppress broader features such as channels while still running Frangi over a wider diagnostic scale range.
drain_log10_abs_accumulation_curvature_blur_radius_metres float 20.0 param - Radius of the moving-window mean used to smooth log10(abs(accumulation_curvature)), in metres. The blurred log10 accumulation-curvature raster is then used for accumulation-curvature masking in the drain finder. Set to 0 to disable smoothing.
drain_response_threshold float 0.15 param - Threshold applied to the Frangi response before shape filtering. Lower values retain more candidate pixels; higher values are more conservative.
drain_min_component_pixels int 6 param - Minimum connected-component size in pixels. Small spotty detections below this size are removed.
drain_min_major_axis_pixels float 5.0 param - Minimum estimated major-axis length in pixels. Retains only components with a sufficiently line-like span.
drain_min_elongation float 3.0 param - Minimum component elongation = major_axis / minor_axis. Higher values more aggressively reject leopard-spot style detections.
write_drain_mask_raster bool true switch - Write the final filtered binary drain mask. Output pixels are 1.0 for retained drain detections and 0.0 otherwise.
write_drain_diagnostic_rasters bool true switch - Write intermediate drain-finder diagnostic rasters. Includes Frangi response, Frangi best scale, and the thresholded candidate mask before shape filtering.
drain_accumulation_curvature_lambda float 4.0 param - Wavelength used for the polyfit accumulation-curvature veto, in metres. Use a scale that captures channel and broken-ground curvature structure without being so large that subtle drains disappear.
drain_accumulation_curvature_z_factor float 1.0 param - Vertical scaling applied before interpreting accumulation curvature. Usually leave at 1.0 unless you deliberately want to amplify or suppress curvature magnitudes.
drain_accumulation_curvature_flat_slope_tolerance float 1e-12 param - Flat-slope tolerance passed to the polyfit metric engine for the accumulation-curvature veto. Very small default so only nearly flat terrain is treated as directionless.
drain_log10_abs_accumulation_curvature_max float -5.0 param - Maximum allowed value of log10(abs(accumulation_curvature)) for retained drain candidates. Pixels above this value are removed from the thresholded Frangi candidates.

Valley finder (SMAP shape classifier on a smoothed DEM)

Parameter Type Default Role Parent Description Guidance
valley_polyfit_lambda_metres float 50.0 param - Smoothing window (polyfit lengthscale) applied before shape classification, in metres. The quadratic-fit window IS the smoothing scale. Larger values (e.g. 50 m) suppress fine channels and retain broad valley forms; smaller values resolve narrower valleys.
valley_curvature_threshold float 0.0 param - Curvature threshold (kt) passed to the SMAP classifier, in 1/m. Principal curvatures with magnitude <= kt are set to zero before classification, collapsing weak/long-wavelength structure toward planar or cylindrical classes. 0 keeps every pixel in a non-planar class.
valley_include_basin bool true param - Include the basin class (SMAP -3, concave bowl) in the valley mask. Concave-up class with mean curvature > 0.
valley_include_synformal_saddle bool true param - Include the synformal-saddle class (SMAP -2) in the valley mask. Concave-up class with mean curvature > 0 and negative Gaussian curvature.
valley_include_synform bool true param - Include the synform class (SMAP -1, cylindrical valley) in the valley mask. The canonical broad-valley form: concave across the contour, straight along it.
write_valley_mask_raster bool true switch - Write the binary valley mask. 1 indicates a pixel in one of the selected concave-up SMAP classes.
write_valley_shape_class_raster bool true switch - Write the full SMAP shape-class raster. Integer codes -4..3 stored as float32 (see surface_shape_class).
write_valley_diagnostic_rasters bool false switch - Write valley-finder diagnostic rasters. Includes the smoothed fitted surface, the principal curvatures, and the post-threshold Gaussian and mean curvatures used by the classifier.

Road finder (along-contour bench detector)

Parameter Type Default Role Parent Description Guidance
road_polyfit_lambda_metres float 8.0 param - Smoothing window (polyfit lengthscale) for road detection, in metres. Roads are narrow, so use a small window matched to the bench width (cut-to-fill cross-section). Larger values blur the bench edges.
road_flat_slope_tolerance float 1e-4 param - Gradient magnitude below which the local aspect is treated as undefined. On near-flat ground the contour direction is meaningless, so such pixels are gated out of the road score.
road_min_elongation float 0.3 param - Minimum Hessian line-likeness for retained road pixels. elongation = (|lam_major| - |lam_minor|) / (|lam_major| + |lam_minor|). Higher values demand a more strongly linear curvature signature.
road_min_contour_alignment float 0.7 param - Minimum alignment between the feature's long axis and the contour direction. |along_feature . contour_unit| in [0,1]. ~1 for along-contour features (roads/benches); ~0 for down-slope features (channels). Raise to be stricter.
road_curvature_half_saturation float 0.1 param - Half-saturation curvature (1/m) for the edge-strength weight in the road score. edge_strength = |cross_curvature| / (|cross_curvature| + this). Smaller values let gentler curvature breaks score highly; larger values demand sharper edges. Set to 0 to disable the edge-strength weighting entirely.
road_min_cross_curvature float 0.05 param - Minimum cross-feature curvature magnitude (1/m) for retained road pixels. 0 disables the floor. Use to suppress featureless slopes with no real edge.
road_max_cross_curvature float 0.0 param - Maximum cross-feature curvature magnitude (1/m) for retained road pixels. 0 disables the cap. Use to exclude deeply incised channels and cliffs that have very high cross-curvature.
road_score_threshold float 0.5 param - Threshold applied to the road score to make a binary mask. score = elongation * contour_alignment * edge_strength. Lower is more inclusive.
road_use_bench_test bool true param - Require road pixels to be a narrow flat ribbon (bench) on a slope. Samples slope a short distance to each side along the cross-feature direction; both flanks must be steeper than the tread. This is what rejects floodplains and valley floors, which are flat on one flank.
road_bench_half_width_metres float 6.0 param - Cross-feature sampling distance for the bench test, in metres. Set a little larger than the road half-width plus its cut/fill batter so the samples land on the flanking slopes, not on the tread.
road_bench_flank_slope_ratio float 1.5 param - Bench test: required ratio of flank slope to tread slope. Both flanks must have slope >= ratio * tread_slope (and >= road_bench_min_flank_slope). Higher demands a flatter tread relative to its flanks.
road_bench_min_flank_slope float 0.15 param - Bench test: minimum absolute flank slope (tan of slope angle). Both flanks must be at least this steep (0.15 ~ 8.5 degrees). Guards against near-flat terrain passing the ratio test when the tread slope is ~0.
write_road_score_raster bool true switch - Write the continuous road score raster. score = elongation * contour_alignment, gated by slope/curvature.
write_road_mask_raster bool true switch - Write the thresholded binary road mask. 1 indicates a plausible along-contour bench/road pixel.
write_road_diagnostic_rasters bool false switch - Write road-finder diagnostic rasters. Includes contour alignment, Hessian elongation, cross-feature curvature, along-feature orientation (azimuth from grid north, or true north with bearings_relative_to_true_north), and slope.

Flow-pathway road/channel discrimination

Parameter Type Default Role Parent Description Guidance
flow_regional_polyfit_lambda_metres float 100.0 param - Smoothing window (polyfit lengthscale) for the regional slope vector, in metres. A large window (e.g. 100 m) gives the regional fall-line bearing that flow paths are compared against.
flow_path_half_window int 5 param - Number of pixels traced up- and downstream when measuring the flow-path bearing. The bearing is taken over a window of (2*this + 1) pixels along the D8 path (default 5 gives an 11-pixel segment).
flow_short_curvature_radius_metres float 0.0 param - Radius for the short-wavelength tangential curvature, in metres. The short polyfit half-wavelength is 2 * this radius; 0 uses ~3 pixels. Output: _flow_short_tangential_curvature.<ext>.
flow_intermediate_polyfit_lambda_metres float 15.0 param - Polyfit window (lengthscale) for the intermediate curvature rasters, in metres. Produces tangential, minimum, and maximum curvature at this scale. Outputs: _flow_intermediate_tangential_curvature.<ext>, _flow_intermediate_minimum_curvature.<ext>, _flow_intermediate_maximum_curvature.<ext>.
flow_roughness_radius_metres float 2.5 param - Window radius for the local roughness (elevation standard deviation), in metres. Roads are smoother than the surrounding landscape, so they show low roughness.
write_flow_discrimination_rasters bool true switch - Write the flow-pathway discrimination diagnostic rasters. Outputs: regional slope bearing and gradient, contributing pixels, channel mask, flow-path bearing, flow-vs-slope angle, short gradient, short total curvature, roughness, bearing contrast, and the valley-axis buffer mask.
flow_valley_curvature_metric string tangential_curvature param - Regional curvature used to define the valley zone. tangential_curvature (default): cross-slope/contour curvature (flow convergence) - picks valleys but NOT footslope slope breaks (those are concave down-slope only). plan_curvature: similar but normalised differently. laplacian or mean_curvature: total concavity - also flags slope breaks. Positive = concave; ridges (convex) are always excluded by sign.
flow_valley_curvature_threshold float 0.0 param - Regional (smoothed) curvature above which a pixel is in the valley zone, in 1/m. Uses flow_valley_curvature_metric of the heavily smoothed surface: concave-up (>= this) is the valley zone and convex-up (ridges) is excluded. 0 keeps every concave pixel; raise to restrict to stronger valley convergence.
flow_valley_require_bearing_contrast bool false param - Also require the bearing-contrast gate when building the valley-axis mask. Off by default. On its own, bearing contrast only fires on sharp bearing flips (missing broad valleys) and cannot separate valleys from ridges; the regional curvature does that. Enable only to further restrict the valley zone.
flow_bearing_contrast_window_metres float 10.0 param - Window radius for the regional-bearing-contrast metric, in metres. contrast = 1 - |mean unit-vector of the regional bearing| over this window. High where the bearing flips, e.g. two valley sides facing each other.
flow_bearing_contrast_threshold float 0.4 param - Bearing-contrast value above which a pixel is flagged as a valley/ridge axis. 0 (no contrast) to 1 (opposing bearings). 0.4 captures clear facing-slope axes.
flow_valley_buffer_radius_metres float 10.0 param - Dilation buffer applied around bearing-contrast axes, in metres. Marks the valley-axis zone where flow-path bearings are expected to be ambiguous (not road misdirection).
big_channel_threshold_contributing_pixels int 5000 param - Contributing-pixel threshold for the valley-channel point export. Channel pixels with more than this many upslope pixels that fall inside the valley-axis buffer are exported to a FlatGeobuf point layer.
flow_divergent_export_min_angle float 0.0 param - Minimum flow-vs-slope angle (deg) for a channel pixel to be exported as a point. 0 exports every channel pixel (with its angle attribute) so it can be styled in a GIS; raise to export only the divergent (road-like) pixels.
write_flow_divergent_points_fgb bool true switch - Export channel pixels (with flow-vs-slope angle) to a FlatGeobuf point layer. Output: <write_fname>_flow_divergent_points.fgb. Attributes: row, col, contributing_px, flow_vs_slope_angle, flow_bearing, regional_bearing.
write_flow_valley_channel_points_fgb bool true switch - Export large channel pixels inside the valley-axis buffer to a FlatGeobuf point layer. Output: <write_fname>_flow_valley_channel_points.fgb. Selects channel pixels with contributing pixels > big_channel_threshold_contributing_pixels that lie within the bearing-contrast buffer. Attributes: row, col, contributing_px, flow_vs_slope_angle, bearing_contrast.

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.

Pit filling

Parameter Type Default Role Parent Description Guidance
raster_is_filled bool false switch - Assert that the input raster has ALREADY been pit-filled. ASKS: has the input already been filled? Filling is REQUIRED for this analysis, so this switch does not choose whether to fill -- it only lets the tool skip filling a surface that is filled already. Setting it true for a DEM that still contains pits gives BAD routing, not different routing. Do not confuse this with fill_before_routing, which asks whether to fill at all.

Path opening (generic curvilinear-feature filter)

Parameter Type Default Role Parent Description Guidance
path_min_length_pixels int 15 param - Minimum path length L, in pixels, for the grayscale path opening. A pixel is kept only if it lies on a connected, near-straight path of at least L pixels in the input response. Set near the shortest real road/channel segment to keep; larger L removes more isolated speckle but also drops short fragments.
path_quantization_levels int 256 param - Number of grayscale threshold levels for the path opening. Higher values preserve the input value range more finely at higher cost. 256 is usually plenty for a continuous response raster.
path_trim_border_pixels int 0 param - Trim this many pixels in from the valid-data boundary before the path opening (0 = no trim). Removes the boundary-margin artefacts that polyfit/flow/FFT response rasters carry. Because those artefacts are laterally continuous they otherwise survive the path opening and masquerade as features. Trims from both the grid edge and any irregular nodata footprint.
path_do_closing bool false param - Run a path closing instead of a path opening. A closing fills short dark breaks across an otherwise continuous bright thread (e.g. a one-pixel gap in a road). Opening (default) suppresses isolated bright speckle that lies on no long path.
write_path_opened_raster bool true switch - Write the path-opened (or path-closed) response raster. Output: <write_fname>_path_opened.<ext>.
write_path_tophat_raster bool true switch - Write the white top-hat residual (input minus path opening). The path OPENING (_path_opened.<ext>) is the detector: it retains the long, laterally continuous bright threads (roads/channels) and suppresses isolated speckle. The top-hat is the complement: high where bright detail was REMOVED, i.e. the short-scale speckle and blobs that do NOT lie on a length-L path. Useful as a rejected-noise map or to flatten background before thresholding. Output: <write_fname>_path_tophat.<ext>. Only meaningful for a path opening (not a closing).

Structure-tensor coherence (orientation / line-likeness)

Parameter Type Default Role Parent Description Guidance
coherence_derivative_radius_metres float 0.0 param - Pre-smoothing radius for the gradient in the structure tensor, in metres. 0 = no pre-smoothing (central difference on the raw field). Use a small value (~1 pixel) to suppress gradient noise on speckly inputs.
coherence_integration_radius_metres float 2.5 param - Tensor-averaging (integration) radius for the structure tensor, in metres. THE key scale: the neighbourhood over which the gradient outer product is pooled. Set near the feature half-width plus a few pixels. Larger values give smoother, more confident coherence but blur close features.
write_coherence_raster bool true switch - Write the structure-tensor coherence raster (line-likeness, [0,1]). Output: <write_fname>_coherence.<ext>.
write_orientation_raster bool true switch - Write the structure-tensor orientation raster (feature azimuth, [0,180) deg). Azimuth clockwise from grid north (true north with bearings_relative_to_true_north) along which the feature runs. Meaningful only where coherence is high. Output: <write_fname>_orientation_deg.<ext>.
write_energy_raster bool false switch - Write the structure-tensor energy raster (gradient energy, lam1+lam2). Distinguishes strong from faint oriented structure. Output: <write_fname>_energy.<ext>.

Track spacing (local directional periodicity)

Parameter Type Default Role Parent Description Guidance
spacing_window_pixels int 64 param - Analysis window side length for the spacing detector, in pixels. Must span several periods of the largest spacing of interest (a few times spacing_max_metres / cell_size).
spacing_step_pixels int 32 param - Window stride for the spacing detector, in pixels. Smaller = smoother and slower; typically half the window size.
spacing_min_metres float 5.0 param - Shortest repeat spacing to search for, in metres. Must be >= 2 * cell_size (Nyquist).
spacing_max_metres float 30.0 param - Longest repeat spacing to search for, in metres. Must be <= spacing_window_pixels * cell_size.
spacing_min_valid_fraction float 0.6 param - Minimum fraction of valid pixels for a window to be analysed. Windows with more nodata than this are skipped.
write_spacing_strength_raster bool true switch - Write the periodicity strength (peak prominence) raster. High where a sharp regular spacing dominates. Output: <write_fname>_spacing_strength.<ext>.
write_spacing_raster bool true switch - Write the dominant spacing raster, in metres. Use to classify feature families (ditches vs tracks vs wave dams). Output: <write_fname>_spacing_metres.<ext>.
write_spacing_orientation_raster bool false switch - Write the spacing orientation raster (line azimuth, [0,180) deg). Output: <write_fname>_spacing_orientation_deg.<ext>.

Ridge lines (oriented NMS + hysteresis)

Parameter Type Default Role Parent Description Guidance
ridge_high_threshold float 40.0 param - Strong-seed threshold (in input response units) for ridge hysteresis. Thinned-response pixels at or above this start a retained centreline. Set relative to the input raster's value range.
ridge_low_threshold float 20.0 param - Weak-link threshold (in input response units) for ridge hysteresis. Thinned pixels at or above this are kept only if connected to a strong seed. Must be <= ridge_high_threshold.
ridge_min_coherence float 0.0 param - Minimum structure-tensor coherence to admit a pixel to the ridge response. Pixels with coherence below this are zeroed before NMS, removing ridge maxima that sit in incoherent speckle. 0 disables the gate. Uses the coherence_*_radius_metres parameters for the tensor scale.
write_ridge_thinned_raster bool true switch - Write the NMS-thinned ridge response (1-pixel centrelines, response-valued). Output: <write_fname>_ridge_thinned.<ext>.
write_ridge_mask_raster bool true switch - Write the binary hysteresis-linked ridge centreline mask. Enabled by default because this is a primary product of the ridge-finder stage, not the optional hilltop diagnostic exposed by the coupling CLI. Output: <write_fname>_ridge_mask.<ext>.

Thin-line extractor (separate lines from blobs/speckle)

Parameter Type Default Role Parent Description Guidance
thin_threshold float 20.0 param - Threshold to binarise the input response (keep response >= this). -
thin_directional_closing_length_pixels int 0 param - Line length (pixels) for directional closing to bridge gaps along lines (0 = skip). Reconnects fragmented features before component analysis.
thin_path_length_pixels int 40 param - Binary path-opening length L (pixels); 0 = skip. THE primary thin-vs-blob/speckle tool: keeps pixels on a connected thin path of at least L pixels (handles curves); removes speckle and any blob lacking such a path. Set near the shortest road to keep.
thin_blob_removal_radius_metres float 0.0 param - Disk-opening top-hat radius (metres) to remove blobs wider than this (0 = skip). THE thin-vs-blob filter: features wider than ~2x this radius (blobs, wide patches) are removed; thinner ribbons (roads) survive. Set a little above the widest real road half-width.
thin_min_component_pixels int 40 param - Minimum connected-component size (pixels). -
thin_min_major_axis_pixels float 0.0 param - Minimum component major-axis length (pixels); 0 = skip. -
thin_min_elongation float 1.0 param - Minimum component elongation = major/minor axis; 1 = skip. Raise (e.g. 3) to keep only clearly linear components and drop compact residue.
thin_trim_border_pixels int 0 param - Trim this many pixels from the final mask border (0 = none). Removes linear edge artefacts that survive the elongation filter.
write_thin_mask_raster bool true switch - Write the final thin-line mask. Output: <write_fname>_thin_mask.<ext>.
write_thin_diagnostic_rasters bool false switch - Write the thresholded binary and the blob-removed intermediate. -

Generic roughness / consistency of an input raster

Parameter Type Default Role Parent Description Guidance
roughness_input_radius_metres float 5.0 param - Moving-window radius for the roughness/consistency metric, in metres. Larger windows pool more context (smoother result).
roughness_circular bool false param - Treat the input as a circular angle in degrees (e.g. a flow bearing). When true, computes circular consistency R = |mean unit-vector| over the window (1 = perfectly consistent direction, e.g. flow channelled along a road; 0 = directions cancel). Writes consistency (R) and roughness (1-R). When false, computes the linear moving-window standard deviation.
write_roughness_raster bool true switch - Write the roughness raster (stddev, or 1-R for circular input). Output: <write_fname>_input_roughness.<ext>.
write_consistency_raster bool true switch - Write the circular consistency raster R (only for roughness_circular=true). High where the angle is locally consistent. Output: <write_fname>_input_consistency.<ext>.

Smoothness road extractor (roads = smooth ribbons)

Parameter Type Default Role Parent Description Guidance
smooth_roughness_radius_metres float 1.5 param - Window radius for the local-relief roughness, in metres. Match to the hillslope speckle scale. Roads are smooth (low roughness) ribbons; the surrounding terrain is rough.
smooth_roughness_half_saturation float 0.1 param - Roughness half-saturation (metres) for smoothness = 1/(1+roughness/h). Roughness equal to this gives smoothness 0.5. Lower = more selective for very smooth surfaces; set near the road-vs-hillslope roughness boundary.
smooth_trim_border_pixels int 10 param - Border trim applied before extraction (0 = none). -
smooth_path_min_length_pixels int 40 param - Minimum path length L (pixels) for the smoothness path opening. Keeps smooth ribbons at least this long; drops short smooth patches.
smooth_threshold float 0.5 param - Threshold on the path-opened smoothness to make the binary ribbon mask. Higher = only the smoothest ribbons; lower = more inclusive.
smooth_min_component_pixels int 40 param - Minimum connected-component size (pixels) for a retained road. -
smooth_min_major_axis_pixels float 0.0 param - Minimum component major-axis length (pixels); 0 = skip. Use to demand a minimum linear span.
smooth_min_elongation float 1.0 param - Minimum component elongation = major/minor axis; 1 = skip. Raise (e.g. 3) to reject smooth blobs (fields) and keep thin roads.
write_smooth_road_mask_raster bool true switch - Write the final smoothness-based road mask. Output: <write_fname>_smooth_road_mask.<ext>.
write_smooth_diagnostic_rasters bool false switch - Write roughness, smoothness, and path-opened smoothness diagnostics. -

Road extractor (composed pipeline)

Parameter Type Default Role Parent Description Guidance
road_trim_border_pixels int 15 param - Border trim applied to the response before road extraction (0 = none). Removes boundary-margin artefacts that otherwise survive as linear features.
road_min_coherence float 0.5 param - Minimum structure-tensor coherence to admit a pixel to the ridge response. Pixels below this are zeroed before NMS, removing ridge maxima in incoherent speckle. 0 disables the gate.
road_min_component_pixels int 30 param - Minimum connected-component size (pixels) for a retained road. Drops short speckle fragments left by the ridge detector while keeping long road chains. Set near the shortest real road length in pixels.
road_valley_curvature_fname string - param - Optional regional-curvature raster for the valley veto (relative to read path). Typically <prefix>_flow_regional_valley_curvature.<ext> from flow_road_discrimination. Empty = no valley veto. Centreline pixels where this raster >= road_valley_curvature_veto_threshold are removed.
road_valley_curvature_veto_threshold float 0.0 param - Curvature threshold for the valley veto (sign per the supplied raster). Centreline pixels with regional curvature >= this (concave-up valley zone) are dropped, removing the in-valley channel false positive.
road_classify_spacing bool false param - Classify each extracted component as road (1) or regularly-spaced track (2). Runs the directional-periodicity detector on the response and labels a component a track when at least road_track_min_fraction of its pixels lie in a field with periodicity strength >= road_track_min_strength. Uses the spacing_* parameters. Output: <write_fname>_road_extract_classified.<ext>.
road_track_min_strength float 6.0 param - Periodicity strength above which a pixel counts as 'in a regular field'. See track_spacing strength (whitened directional anisotropy). Raise to demand stronger regularity before calling a component a track.
road_track_min_fraction float 0.5 param - Fraction of a component's pixels that must be 'in a regular field' to label it a track. Higher = stricter (only components mostly inside a regular field become tracks). Ignored when road_classify_per_pixel is true.
road_classify_per_pixel bool false param - Classify per pixel instead of per connected component. false (default): whole component voted road/track (consistent per feature but diluted where roads and tracks connect). true: each pixel is a track where its local periodicity strength >= road_track_min_strength (no dilution; road_track_min_fraction is ignored).
write_road_extract_mask_raster bool true switch - Write the final extracted road mask. Output: <write_fname>_road_extract_mask.<ext>.
write_road_extract_diagnostic_rasters bool false switch - Write road-extractor intermediate rasters. Diffused response, coherence, NMS-thinned ridge, and the pre-cleanup ridge mask.

Coherence-enhancing diffusion

Parameter Type Default Role Parent Description Guidance
ced_iterations int 10 param write_diffused_raster Number of coherence-enhancing diffusion iterations. More iterations bridge longer gaps and smooth more strongly along feature orientation.
ced_time_step float 0.15 param write_diffused_raster Explicit diffusion time step (tau). Must be in (0, 0.25] for stability. 0.15 is a safe default.
ced_derivative_radius_metres float 0.5 param write_diffused_raster Gradient pre-smoothing radius for the diffusion structure tensor, in metres. 0 = none. A small value steadies the orientation estimate on noisy input.
ced_integration_radius_metres float 3.0 param write_diffused_raster Structure-tensor integration radius for the diffusion, in metres. Sets the scale over which a coherent orientation is detected before smoothing along it.
ced_contrast float 0.2 param write_diffused_raster Coherence contrast (C) controlling along-feature smoothing selectivity. Uses normalised coherence in [0,1], so C is scale-invariant. Higher = smooth only the most coherent threads; lower = smooth more of the field.
ced_min_diffusivity float 0.001 param write_diffused_raster Floor (across-feature) diffusivity for the diffusion tensor. Small value in (0,1); controls the tiny amount of smoothing allowed across the feature.
write_diffused_raster bool true switch - Write the coherence-enhanced (diffused) raster. Output: <write_fname>_diffused.<ext>.

Riser finder (find_risers)

Parameter Type Default Role Parent Description Guidance
riser_search_mask_fname string - param - Raster restricting where risers are looked for (cells > 0.5). Empty (default) = every valid DEM cell. Typically the flat mask from lsdtt-flat-surface-finder, so risers are only sought between surfaces. Must be on the DEM grid. Gap-closing bridges may cross ground outside the mask - a road cut out of it is exactly the gap a riser needs closing across.
riser_edge_metric string vertical_excess_curvature param - Edge field the riser lines are drawn on: vertical_excess_curvature, curvedness, maximum_curvature or multidirectional_hillshade. All are high on a riser and low on a tread. The first three come from the polyfit (riser_polyfit_lambda_metres): vertical_excess_curvature is k_v - k_min, curvedness sqrt((k_max^2 + k_min^2) / 2), maximum_curvature |k_max|. multidirectional_hillshade is the mean hillshade over multidirectional_hillshade_n_directions azimuths, negated so steep is high (3x3 on the DEM, no polyfit). Whichever is chosen goes through the same threshold, skeleton and step-height filter, so a gully wall with no tread either side is still dropped.
multidirectional_hillshade_n_directions int 8 param riser_edge_metric Number of evenly spaced azimuths for riser_edge_metric multidirectional_hillshade. Same meaning as in lsdtt-raster-preprocessing.
riser_polyfit_lambda_metres float 100 param - Polyfit half-wavelength (m) for the polyfit edge metrics (riser_edge_metric), and the default step window. Larger values smooth more and move the detected line further off the step itself; the step window follows it (riser_step_window_radius_metres).
riser_vec_adaptive_method string mean_std param - Adaptive threshold applied to the edge field (riser_edge_metric): mean_std, mean or gaussian. mean_std: foreground where the field exceeds the local mean plus riser_vec_adaptive_std_factor local standard deviations over the block, in the field's own units (the standard deviation floored at 1/255 of the field's range, so a smooth tread's noise does not pass). mean / gaussian: the field rescaled to 0-255 grey levels between its minimum and maximum, foreground above the local box / Gaussian mean minus riser_vec_adaptive_C (cv::adaptiveThreshold). With a heavy upper tail the rescaling squeezes the treads into a few grey levels and 'above the local mean' picks up noise across them, which breaks risers into short pieces.
riser_vec_adaptive_std_factor float 0.5 param riser_vec_adaptive_method Local standard deviations above the local mean for the mean_std threshold. Larger is stricter.
riser_vec_adaptive_block_size_pixels int 51 param - Neighbourhood block size (pixels) for adaptive thresholding. Must be odd and >= 3. Larger than a riser's width, smaller than the spacing between risers.
riser_vec_adaptive_C float 0.0 param riser_vec_adaptive_method Offset (grey levels) for the mean and gaussian thresholds. In grey levels of the field rescaled to 0-255 between its minimum and maximum, rounded up to an integer: foreground where grey level > local mean - ceil(C). Negative = stricter; any C in (-1, 0] acts as 0. Not used by mean_std.
riser_vec_adaptive_gaussian_sigma float 0.0 param riser_vec_adaptive_method Sigma (pixels) of an optional Gaussian pre-blur before the mean and gaussian thresholds. 0 = no blur. Applied to the 8-bit image; not used by mean_std.
riser_closing_radius_metres float 0 param - Closing radius (m) applied to the thresholded mask before thinning. Seals small gaps in the detected regions. 0 = disabled.
riser_binary_min_component_pixels int 1 param - Minimum component size (pixels) kept in the thresholded mask. Applied before thinning. 1 = keep all.
riser_max_spur_pixels int 10 param - Longest endpoint-rooted spur (pixels) pruned from the skeleton. 0 = no spur pruning. Pruning also trims this much off every free end, so gaps open by about twice this before gap closing sees them.
riser_max_terminal_loop_pixels int 10 param - Longest terminal loop (pixels) pruned from the skeleton. 0 = no loop pruning.
riser_min_component_pixels int 1 param - Minimum skeleton component size (pixels) kept after pruning. -
riser_gap_closing_algorithm_choice string none param - How broken risers are joined: none or astar. astar routes a least-cost bridge along the contour between two skeleton endpoints within riser_connect_search_radius_metres whose elevations differ by at most riser_connect_elevation_tolerance_metres.
riser_connect_search_radius_metres float 200 param riser_gap_closing_algorithm_choice Longest straight-line gap (m) an astar bridge may close. -
riser_connect_elevation_tolerance_metres float 2 param riser_gap_closing_algorithm_choice Largest elevation difference (m) between two bridged endpoints. Also the contour band the bridge is routed in. Keep it below the smallest riser height, or a bridge can join risers at different heights.
riser_connect_corridor_half_width_pixels float 12 param riser_gap_closing_algorithm_choice Half-width (pixels) of the corridor an astar bridge is routed in. -
riser_connect_same_component bool false param riser_gap_closing_algorithm_choice Allow bridges between two endpoints of the same skeleton component. Default false: only between different components.
riser_step_window_radius_metres float 0 param - Step window d (m) for the step height across each segment. step = |2 dz(d) - dz(2d)|, dz(r) the elevation difference between r either side along the normal: 0 on any planar slope, the step H across a riser between two treads of the same tilt. 0 (default) = half riser_polyfit_lambda_metres, at least three cells: the line sits on the curvature maximum, which the polyfit moves off the step, and d must reach past it to both treads.
riser_min_step_height_metres float 1 param - Segments with a smaller median step height (m) are dropped. Without a height floor an adaptive threshold finds a line in any noise.
riser_min_segment_pixels int 5 param - Segments with fewer pixels are dropped. -
write_riser_centreline_raster bool true switch - Write the kept riser segments as a 1/0 raster. Output: <write_fname>_riser_centreline.<ext>. Feed it to lsdtt-fluvial-surfaces riser_mask_fname.
write_riser_segments bool true switch - Write the kept riser segments as a line layer. Output: <write_fname>_riser_segments.<fgb|gpkg>. Fields: segment_id, n_pixels, length_m, step_height_m (median step), face_gradient (median steepest gradient across the riser, m/m, as the grid resolves it), mean_elevation_m, is_loop. Risers rarely close: these are open lines, not polygons.
write_riser_endpoints bool false switch - Write the free ends of the kept riser segments as a point layer. Output: <write_fname>_riser_endpoints.<fgb|gpkg>. Fields: row, col, elevation_m.
write_riser_diagnostic_rasters bool false switch - Write the riser finder's intermediate rasters. Outputs: <write_fname>_riser_edge_field (the riser_edge_metric field), _riser_adaptive_binary, _riser_skeleton and, under astar, _riser_gap_closing (pixels added by bridges).
mapped_risers_fname string - param - Mapped terrace edges / risers (lines; gpkg, fgb, shp) to score the detected risers against. Burned into the DEM grid by every cell a line touches, reprojected to the DEM CRS. A detected riser cell counts as found when a mapped cell lies within mapped_risers_tolerance_metres of it, and a mapped cell as recovered when a detected cell does. Writes <write_fname>_mapped_risers.tif (the burned lines) and <write_fname>_mapped_riser_scores.csv: per scope the cell counts, precision (detected cells near a mapped edge), recall (mapped cells near a detected riser) and F1. Scope 'extent' is every valid cell inside mapped_risers_extent_fname; scope 'search_mask' (only with riser_search_mask_fname) is those cells inside the search mask too, where a riser could have been found at all.
mapped_risers_extent_fname string - param mapped_risers_fname Polygon(s) of the area the mapper actually surveyed. Cells whose centre is outside are not scored, so a riser where nobody mapped is not a false detection. Empty: the whole DEM counts as surveyed (the log says so).
mapped_risers_tolerance_metres float 20 param mapped_risers_fname Largest distance (m) between a detected riser cell and a mapped edge cell for them to count as the same line. Centre to centre. Covers the digitising error of the map and the finder's own offset from the step (riser_polyfit_lambda_metres moves the line off the face); two cells on a 10 m grid is a strict start.

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.

Orientations

Parameter Type Default Role Parent Description Guidance
bearings_relative_to_true_north bool false param - Write bearings, aspects and orientations clockwise from true north. Off (default): they are clockwise from grid north (grid up), so in an oblique frame with the feature along +x, 90 degrees means along the feature. On: each value is converted with the grid convergence at its own location (each cell of a raster, each row of a table), which also removes the up to about 3 degree difference between UTM grid north and true north. Angles between two directions (junction angles, deflections, contrasts) are unchanged, and hillshade illumination always stays relative to grid up. Needs a raster with a CRS.

Output

Parameter Type Default Role Parent Description Guidance
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.