Workflow: valley-floor widths
The valley_widths workflow takes one DEM or a folder of them, and for each one:
- finds the floodplain with
lsdtt-fluvial-surfaces; - traces a valley centreline down every channel segment, and casts cross
sections across it, with
lsdtt-valley-centreline(run_valley_width_network). Each section's width is the span of the floodplain it crosses; - draws maps and profiles with lsdviztools3, if it is installed;
- gathers every DEM's widths into one table and a per-DEM summary.
Set up the Snakemake environment first: see Workflows. The methods themselves are described in Floodplains, terraces and valleys.
Figures need lsdviztools3
The figures listed on this page are drawn only if lsdviztools3 is installed and the workflow can find it (how to set it up, step 4). Without it the run says the figures were skipped and writes everything else.
Quick start
From the repository root, the shipped example fetches a 30 m Copernicus DEM of a stretch of the River Spey in Scotland and runs the whole chain:
pixi run -e workflows snakemake --cores 1 --snakefile workflows/Snakefile \
--directory workflows --configfile workflows/config/valley_widths.yaml
Results are in workflows/results/valley-widths-example/.
Running it on your own DEMs
- Put the DEMs in one folder. They must be in a projected coordinate
system in metres (UTM, a national grid), with nodata set. The file stem
names the DEM in every output (
glen_a.tif->glen_a), so use names without spaces. -
Copy the config:
cp workflows/config/valley_widths.yaml workflows/config/my_valleys.yaml -
In the copy, set
run_id, setdem_dirto your folder (an absolute path is safest), and delete thedems:block, which holds the example. With nodems, every file indem_dirmatchingdem_globis processed. - Set the channel threshold for your resolution (next section).
-
Dry run with
-n, then run:pixi run -e workflows snakemake -n --cores 1 --snakefile workflows/Snakefile \ --directory workflows --configfile workflows/config/my_valleys.yaml pixi run -e workflows snakemake --cores 1 --snakefile workflows/Snakefile \ --directory workflows --configfile workflows/config/my_valleys.yaml
Add DEMs to the folder later and run again: only the new ones are processed, and then the combined table is rebuilt.
The parameters that matter most
Every block in the config is copied into the tool's parameter file as written; Changing the parameters explains how, and how to give one DEM its own values.
Channel threshold (shared_parameters.threshold_contributing_pixels).
It sets where channels start, so it decides which valleys are measured. It is
given to both tools so they use the same network. It counts pixels, so the
same drainage area needs a different number at each resolution:
| Channel heads at | 30 m DEM | 10 m DEM | 5 m DEM | 1 m DEM |
|---|---|---|---|---|
| 0.1 km² | 111 | 1000 | 4000 | 100000 |
| 1 km² | 1111 | 10000 | 40000 | 1000000 |
If the DEMs have different resolutions, give each its own value under dems:.
Floodplain method (fluvial_surfaces.fluvial_surface_algorithm_choice).
The default config uses clubb2017: floodplain = pixels low above the nearest
channel (HAND) and gentle, with both bounds read off quantile-quantile plots
(Clubb et al., 2017), in patches that touch a channel.
floodplain_second_pass_algorithm_choice: qq_upper_departure then trims fans
and low terraces from that first pass. Set it to none to keep the first-pass
floodplain. The bounds used are written to
<dem>_floodplain_thresholds.csv. clubb2017 defines channels by Strahler
order (min_channel_stream_order, 3), and stops with a message if the network
never reaches that order. Lower the order, or the channel threshold, if it does.
Which mask the width is measured against (width_mask). floodplain
(the default) measures the valley floor. valley measures the wider valley
mask, which takes in terraces.
Cross sections (valley_centreline):
| Parameter | Default here | Effect |
|---|---|---|
cross_section_spacing_metres |
100 | Distance between sections along each centreline |
write_valley_cross_sections |
true |
Section lines and the elevation profile along each one |
write_cross_section_features |
false |
Valley walls, channel crossings and slope breaks along each section |
write_cross_section_hydraulics |
false |
Stage-by-stage flow width, area and hydraulic depth of each section |
network_centreline_algorithm_choice |
medial_path |
medial_path follows the middle of the valley floor; smoothed_channel smooths the channel itself, kept inside the mask |
write_relative_elevation_raster |
false |
Elevation above the centreline's baseline, within the mask |
Figures. When lsdviztools3
is found, each DEM also gets a map of the sections coloured by
excluded_reason, a width profile down the largest trunk, a map of the
channels and centrelines, the floodplain over a hillshade, and the HAND QQ
plots its bounds were read from. Without lsdviztools3 the widths are still
computed, and the run says the figures were skipped. See
Figures for how lsdviztools3 is found.
Outputs
For each DEM, in workflows/results/<run_id>/<dem>/:
| File | Contents |
|---|---|
floodplain/<dem>_floodplain_mask.tif |
The floodplain the widths are measured against |
floodplain/<dem>_floodplain_polygons.fgb |
The same as polygons |
floodplain/<dem>_floodplain_thresholds.csv |
HAND and gradient bounds used |
floodplain/<dem>_reference_field.tif |
HAND (m) |
floodplain/<dem>_surface_class.tif |
0 none, 1 floodplain, 2 terrace |
widths/<dem>_valley_widths.csv |
One row per cross section: segment, distance along the centreline, left and right half-widths, valley_width_m, channel elevation and drainage area at the station, and excluded_reason |
widths/<dem>_valley_segments.csv |
One row per channel segment: parent segment, nesting depth, head and end, a width estimate |
widths/<dem>_valley_centreline.fgb |
One centreline per segment |
widths/<dem>_valley_segment_channels.fgb |
Each segment's channel |
widths/<dem>_valley_cross_sections.fgb |
Section lines, with the same fields as the width table |
widths/<dem>_valley_cross_section_samples.csv |
Elevation samples along every section: offset from the centreline, elevation, whether in the valley. These are the cross-section profiles |
figures/<dem>_valley_widths_map.png, _profile.png, _channels.png, <dem>_floodplain_map.png, <dem>_floodplain_hand_qq.png |
When lsdviztools3 is found |
logs/ |
Each tool's log |
And for the whole run, in workflows/results/<run_id>/reports/:
| File | Contents |
|---|---|
all_valley_widths.csv |
Every DEM's width table, with a dem column first |
valley_width_summary.csv |
Per DEM: number of sections, how many were kept and why the others were excluded, kept sections with zero width, and the quartiles of the kept widths |
Which sections to use
Filter the width table on excluded_reason == "none". The other values mark
sections that do not measure a valley floor:
excluded_reason |
Meaning |
|---|---|
not_in_valley |
The channel runs outside the floodplain mask at this station. Usually the most common value: steep reaches have no floodplain |
near_parent_channel |
A tributary's section inside its parent's valley; the parent measures that valley |
tributary_crossing |
A parent's section that runs up a tributary valley |
side_not_found |
No valley edge found within the section's length |
Some kept sections can have valley_width_m 0. The summary counts them
(n_kept_zero_width), so check that number before using the quartiles.
Your own DEMs at different resolutions
valley_widths:
dem_dir: "/data/valleys"
dems:
upper_reach:
file: "upper_reach_5m.tif"
shared_parameters:
threshold_contributing_pixels: 40000
lower_reach:
file: "lower_reach_10m.tif"
shared_parameters:
threshold_contributing_pixels: 10000
valley_centreline:
cross_section_spacing_metres: 200
Once dems: lists any DEM, only the listed DEMs are processed.