Freshwater-specific environmental variables

This tutorial shows you how to calculate stream-specific freshwater variables by relating the upstream e.g. land cover to any given downstream location using the GRASS GIS add-ons & The original 1km data and publication are available here - see also the original code from

Add-on animation

This example contains the following steps:

  • Download an exemplary digital elevation model (DEM)
  • Extract the stream network from the DEM
  • Delineate major drainage basins
  • Crop data to a sub-basin
  • Calculate the sub-watersheds for each stream grid cell (
  • Calculate contiguous stream-specific variables (
The add-ons have been tested in the Linux environment. Microsoft Windows users: consider installing the OSGEO-Live Virtual machine that has GRASS GIS 7 already installed and is ready to use. Alternatively you can run the add-ons via QGIS.

Create and enter the folder where the data will be stored:

export INDIR=$HOME/grass_hydro
mkdir $INDIR 

Download the script

cd ~
wget ""
rstudio &

Download and unzip a DEM from WorldClim:

wget -O  $INDIR/  ""
unzip  -o $INDIR/  -d  $INDIR/dem
gdalinfo $INDIR/dem/alt_16.tif        # check data

If needed, first install the latest GRASS GIS version:

sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable
sudo add-apt-repository ppa:grass/grass-devel
sudo apt-get update
sudo apt-get install grass grass-gui grass-dev subversion gdal-bin libgdal-grass libalgorithms1 libbase1 libgdal-dev

Create the GRASS GIS data base and enter GRASS:

grass78  -text -c $INDIR/dem/alt_16.tif  $INDIR/grass_location

Read data into GRASS: input=$INDIR/dem/alt_16.tif    output=elevation elevation # check data

Open GUI and visualize the layers:

g.gui wxpython

Run hydrological conditioning:

g.extension  extension=r.hydrodem # download extension
# if you get an error run: sudo apt install grass-dev subversion
r.hydrodem  input=elevation  output=elevation_cond

Extract drainage direction and stream network

r.watershed  --h  # see help regarding the options and flags
r.watershed  elevation=elevation_cond  drainage=drainage   stream=stream  accumulation=accumulation  threshold=100  --o

Get drainage basins (last downstream segment: -l flag)

g.extension  direction=drainage  stream_rast=stream  basins=basins_last  -l  --o

Categorize the single basins:

r.clump -d input=basins_last  output=basins_cat  --o

Extract the data for one basin:

r.mapcalc "drainage_sub = if (basins_cat==798, drainage, null() ) "  --o
r.mapcalc "stream_sub = if (basins_cat==798, stream, null() ) "  --o

Write files to disk:

r.out.gdal  input=drainage_sub   output=$INDIR/drainage_sub.tif  type=Int32  nodata=-9999  --o  -c    createopt="COMPRESS=LZW,ZLEVEL=9"
r.out.gdal  input=stream_sub     output=$INDIR/stream_sub.tif    type=Int32  nodata=-9999  --o  -c    createopt="COMPRESS=LZW,ZLEVEL=9"

Create stream-specific variables, and limit the calculation only to a single basin.

Download and install the GRASS add-ons. Work-around (December 2019) for grass78:

mkdir $HOME/.grass7/addons/scripts
wget -O $HOME/.grass7/addons/scripts/ ""
chmod 777  $HOME/.grass7/addons/scripts/

wget -O $HOME/.grass7/addons/scripts/ ""
chmod 777  $HOME/.grass7/addons/scripts/

Add-on 1: Calculate the sub-watershed and sub-stream sections for each stream grid cell using 2 processors: stream=stream_sub  drainage=drainage_sub  cpu=2

Add-on 2: Create stream-specific variables based on elevation  variable=elevation  output=cells,min,max,range,mean,stddev,coeff_var,sum  area=watershed  scale=1  cpu=2

Rename the “elevation_cells” to “flow_accumulation” and check variables:

r.mapcalc "flow_accummulation = elevation_cells"  --o  flow_accummulation  elevation_range

Get stream length (similar procedure as above):  variable=elevation  output=cells  area=stream  scale=1  cpu=2
r.mapcalc "stream_length = elevation_cells"  --o  stream_length 

Calculate the amount of rainfall within the basin:

wget -O  $INDIR/  ""
unzip -q  -o $INDIR/  -d  $INDIR/prec input=$INDIR/prec/prec6_16.tif   output=prec6   # rainfall in June  variable=prec6  output=sum  area=watershed  scale=1  cpu=2

Run all 12 months in a loop:

for var in $(seq 1 12); do input=$INDIR/prec/prec${var}_16.tif   output=prec$var  variable=prec$var  output=sum  area=watershed  scale=1  cpu=2

Other useful add-ons for hydrological applications:

Other examples

Get the stream order:  stream_rast=stream   direction=drainage   strahler=str_order  --o

Get only streams and basins >=3rd order

r.mapcalc "str_order_3rd = if(str_order >=3, str_order, null() ) "  --o  direction=drainage  stream_rast=str_order_3rd  basins=basins_3rd_last   -l  --o

Stream distance - Calculates distance to and elevation above streams and outlet

g.extension   stream_rast=stream   direction=drainage   elevation=elevation_cond  method=downstream   distance=str_distance    difference=str_elevation_diff  --o

Stream order statistics - Calculates Horton’s statistics for Strahler and Horton ordered networks created with Print only order statistics:

g.extension  stream_rast=stream   direction=drainage   elevation=elevation_cond  output=str_stats_o.txt    --o   
more $INDIR/str_stats_o.txt

Print only catchment statistics:  stream_rast=stream   direction=drainage   elevation=elevation_cond  output=str_stats_c.txt    -c 
more $INDIR/str_stats_c.txt

See also these useful GRASS-GIS commands for hydrological applications:*_modules