Aim and Study Area

From a 1m DSM in the Tiraumea catchment, New Zealand, terrain derivatives will be computed with the following code. The aim is to detect Earthflows, possibly through machine learning, where a model would be fed with the terrain derivatives, and optical information.

The study area is shown below:

# Call mapping library and set options
library(mapview)
mapviewOptions(basemaps = 'OpenStreetMap', console = F, verbose = F, leafletWidth = 800)
library(sf, quietly = T, verbose = F, warn.conflicts = F)
tiraumea = st_read('study_area/Tiraumea.shp', quiet = T) 
mapview(tiraumea)

Methods

Earthflows have distinct characteristics that define them, which can somehow be inferred from topographic characteristics. A set of topographic variables have been selected for calculation on the original 1m DSM and on a filter version of it, to 3m. The variables computed are listed below:

List of terrain derivatives computed

list = read.csv('code_list.csv', sep = ';')
library(dplyr, quietly = T)
library(DT)
list %>% arrange(desc(Module), Derivative_Name) %>% datatable()

The naming convention will include the stated name above and for the layers computed based on the 3m filtered window, they will have the suffix 3x3.

Getting started

In order to make the RSAGA workflow work, it is first needed to convert the original DSM into a SAGA compatible format (.sgrd)

dsm = raster('data_rs/2016_HRC_DSM_tiraumea.tif')
writeRaster(dsm, 'terrain/input_dsm/dsm.sgrd', format = 'SAGA', overwrite = T, NAflag = 0, prj = T)

Then, we prepare the RSAGA environment. Currently the SAGA files are on the same project, so there is no need to change the paths. Check that SAGA versions are always compatible when transferring to other computers.

library(RSAGA)
env = rsaga.env(
  path = "software\\saga-7.6.1_x64",
  modules = "software\\saga-7.6.1_x64\\tools"
  # cmd =  "software\\saga-7.6.1_x64\\saga_cmd.exe" # For some reason this throws an error, but when commented out it still works. 
)
Verify specified path to SAGA command line program...
Verify specified path to SAGA modules...
Done

Generating Terrain Derivatives

Initially, we will do a simple filter of the original DSM with a 3x3 window size, to then be able to compute derivatives on all the values.

rsaga.filter.simple(
  in.grid = 'terrain/input_dsm/dsm.sgrd', 
  out.grid = 'terrain/input_dsm/dsm_3x3.sgrd', 
  method = 'smooth', radius = 1, mode = 'square', 
  env = env
)

Below, all the used derivatives will be explained with code, and when needed with additional information. Everything will be computed both for the original DSM and for the filtered 3x3 DSM.

For the Topographic Position Index (tpidx) at a filtered stage, the method required a large computational power. Hence, we resampled the DSM to 3m and calculated it based on that.

dsm = raster('data_rs/2016_HRC_DSM_tiraumea.tif') 

rgbi = stack('data_rs/HRC_2016_RGBI_mosaic_tiraumea.kea')
crs = crs(rgbi)
crs(dsm) = crs

NAvalue(dsm) = -9999

dsm3 = aggregate(dsm, fact = 3)
writeRaster(dsm3, 'data_rs/2016_HRC_DSM_tiraumea_3m.tif')
writeRaster(
  dsm3, 'terrain/input_dsm/dsm_3m.sgrd', format = 'SAGA', overwrite = T, NAflag = 0, prj = T
)

Morphometry module

Slope, Aspect, Curvature module

With this I will compute overall 9 outputs:

  • Aspect (aspect)
  • Slope (slope) in degrees
  • General Curvature (cgene)
  • Plan Curvature (cplan)
  • Profile Curvature (cprof)
  • Crossectional curvature (ccros)
  • Longitudinal curvature (clong)
  • Max. curvature (cmaxi)
  • Min. curvature (cmini)
rsaga.slope.asp.curv(
  in.dem = "terrain/input_dsm/dsm.sgrd", 
  out.aspect = "terrain/out_products/aspect.sgrd",
  out.slope = "terrain/out_products/slope.sgrd",
  out.cgene = "terrain/out_products/cgene.sgrd",
  out.cplan = "terrain/out_products/cplan.sgrd",
  out.cprof = "terrain/out_products/cprof.sgrd",
  out.ccros = "terrain/out_products/ccros.sgrd",
  out.clong = "terrain/out_products/clong.sgrd",
  out.cmaxi = "terrain/out_products/cmaxi.sgrd",
  out.cmini = "terrain/out_products/cmini.sgrd", 
  unit.slope = "degrees", unit.aspect = "degrees",
  env = env,
  method = "poly2zevenbergen"
)

Relative heights and slope positions

From these modules on, we need to find out the usage first, because there are no shortcuts for them. We always refer to this table for the morphometry module to get the respective code:

rsaga.get.modules('ta_morphometry', env = env) %>% knitr::kable()
code name interactive
0 Slope, Aspect, Curvature FALSE
1 Convergence Index FALSE
2 Convergence Index (Search Radius) FALSE
3 Surface Specific Points FALSE
4 Curvature Classification FALSE
5 Hypsometry FALSE
6 Real Surface Area FALSE
7 Morphometric Protection Index FALSE
8 Multiresolution Index of Valley Bottom Flatness (MRVBF) FALSE
9 Downslope Distance Gradient FALSE
10 Mass Balance Index FALSE
11 Effective Air Flow Heights FALSE
12 Diurnal Anisotropic Heat FALSE
13 Land Surface Temperature FALSE
14 Relative Heights and Slope Positions FALSE
15 Wind Effect (Windward / Leeward Index) FALSE
16 Terrain Ruggedness Index (TRI) FALSE
17 Vector Ruggedness Measure (VRM) FALSE
18 Topographic Position Index (TPI) FALSE
19 TPI Based Landform Classification FALSE
20 Terrain Surface Texture FALSE
21 Terrain Surface Convexity FALSE
22 Terrain Surface Classification (Iwahashi and Pike) FALSE
23 Morphometric Features FALSE
24 Valley and Ridge Detection (Top Hat Approach) FALSE
25 Fuzzy Landform Element Classification FALSE
26 Upslope and Downslope Curvature FALSE
27 Wind Exposition Index FALSE
28 Multi-Scale Topographic Position Index (TPI) FALSE
29 Wind Shelter Index FALSE
rsaga.get.usage('ta_morphometry', 14, env = env)

This module will get 5 outputs, and will work with default W, T, E.

  • Slope height (slhgt)
  • Valley depth (vldpt)
  • Normalized height (nrhgt)
  • Standardized height (sthgt)
  • Mid-slope position (mdslp)
rsaga.geoprocessor(
  'ta_morphometry', 14, 
  list(
    DEM='terrain/input_dsm/dsm.sgrd', 
    HO='terrain/out_products/slhgt.sgrd', 
    HU='terrain/out_products/vldpt.sgrd',
    NH='terrain/out_products/nrhgt.sgrd',
    SH='terrain/out_products/sthgt.sgrd',
    MS='terrain/out_products/mdslp.sgrd'
  ),
  env = env
)

Downslope distance gradient

It describes wet areas by assuming water accumulation in flat areas is due to upslope, local and downslope topography. It is a quantitative estimation of the hydraulic gradient. Obtained by calculating the downhill distance when water loses a determined quantity of energy from precipitation.

This tool has its own module, and will return one outcome, coded ‘ddgrd’. We get the usage:

rsaga.get.usage('ta_morphometry', 9, env = env)

And call it, with default distance (10) and gradient in degrees:

rsaga.geoprocessor(
  'ta_morphometry', 9, 
  list(
    DEM='terrain/input_dsm/dsm.sgrd', 
    GRADIENT='terrain/out_products/ddgrd.sgrd', 
    OUTPUT = 2
  ),
  env = env
)

Mass Balance Index

We assume that negative MBI values represent areas of net deposition such as depressions and floodplains; positive MBI values represent areas of net erosion such as hillslopes, and MBI values close to zero indicate areas where there is a balance between erosion and deposition such as low slopes and plain areas. High positive MBI values occur at convex terrain forms, like upper slopes and crests, while lower MBI values are associated with valley areas and concave zones at lower slopes. Balanced MBI values close to zero can be found in midslope zones and mean a location of no net loss or net accumulation of material.

This tool has its own module, and will return one outcome, coded ‘mbidx’. We get the usage:

rsaga.get.usage('ta_morphometry', 10, env = env)

And compute with all the defaults:

rsaga.geoprocessor(
  'ta_morphometry', 10, 
  list(
    DEM='terrain/input_dsm/dsm.sgrd', 
    MBI='terrain/out_products/mbidx.sgrd' 
  ),
  env = env
)

Topographic Position Index

TPI measures the relative topographic position of the central point as the difference between the elevation at this point and the mean elevation within a predetermined neighbourhood. Using TPI, landscapes can be classified in slope position classes. TPI is only one of a vast array of morphometric properties based on neighbouring areas that can be useful in topographic and DEM analysis. Used for roughness determination. The lower the numbers are the lower areas in the landscape. The higher numbers are the higher areas in the landscape. 1

This tool has its own module, and will return one outcome, coded ‘tpidx’. We get the usage:

rsaga.get.usage('ta_morphometry', 18, env = env)

And compute with all the defaults, min and max are definitely needed and vary depending on the raster resolution. If not used properly computation will be exhaustive. Hence, for 1 meter resolution we use 20 and for 3 m, 100 as maximum radious

rsaga.geoprocessor(
  'ta_morphometry', 18, 
  list(
    DEM='terrain/input_dsm/dsm.sgrd', 
    TPI='terrain/out_products/tpidx.sgrd',
    RADIUS_MIN=0,
    RADIUS_MAX=20
  ),
  env = env
)

rsaga.geoprocessor(
  'ta_morphometry', 18, 
  list(
    DEM="terrain/input_dsm/dsm_3m.sgrd",
    TPI='terrain/out_products/tpidx_3m.sgrd',
    RADIUS_MIN=0,
    RADIUS_MAX=100
  ),
  env = env
)

Convergence Index

This module calculates an index of convergence/divergence regarding to overland flow. By its meaning it is similar to plan or horizontal curvature, but gives much smoother results. The calculation uses the aspects of surrounding cells, i.e. it looks to which degree surrounding cells point to the center cell. The result is given as percentages, negative values correspond to convergent, positive to divergent flow conditions. Minus 100 would be like a peak of a cone (a), plus 100 a pit (c), and 0 an even slope (b) 2.

This tool has its own module, and will return one outcome, coded ‘cvidx’. We get the usage:

rsaga.get.usage('ta_morphometry', 1, env = env)

And compute with method gradient and neighbours 3x3:

rsaga.geoprocessor(
  'ta_morphometry', 1, 
  list(
    ELEVATION='terrain/input_dsm/dsm.sgrd', 
    RESULT='terrain/out_products/cvidx.sgrd', 
    METHOD=1,
    NEIGHBOURS=1
  ),
  env = env
)

Terrain Ruggedness Index

Quantitative measure of topographic heterogeneity by calculating the sum change in elevation between a grid cell and its eight neighbor grid cells. This tool works with absolute values by squaring the differences between the target and neighbor cells, then taking the square root. Concave and convex shape areas could have similar values. The value of this metric will vary as a function of the size and complexity of the terrain used in the analysis. The closer you are to 0 the less rugged the terrain likely is. The bigger the number is, eg 105, then the terrain is likely to be more rugged 3

This tool has its own module, and will return one outcome, coded ‘tridx’. We get the usage:

rsaga.get.usage('ta_morphometry', 16, env = env)

And compute with all the defaults:

rsaga.geoprocessor(
  'ta_morphometry', 16, 
  list(
    DEM='terrain/input_dsm/dsm.sgrd', 
    TRI='terrain/out_products/tridx.sgrd'
  ),
  env = env
)

Texture

This parameter emphasizes fine versus coarse expression of topographic spacing, or “grain”… Texture is calculated by extracting grid cells (here, informally, “pits” and “peaks”) that outline the distribution of valleys and ridges. It is defined by both relief (feature frequency) and spacing in the horizontal. Each grid cell value represents the relative frequency (in percent) of the number of pits and peaks within a radius of ten cells (Iwahashi and Pike, 2007. pp.412-413). It should be noted that it is not clear that the relative frequency is actually a percentage. According to Iwahashi and Pike (2007, p.30), To ensure statistically robust classes, thresholds for subdividing the images are arbitrarily set at mean values of frequency distributions of the input variables.

This tool has its own module, and will return one outcome, coded ‘textu’. We get the usage:

rsaga.get.usage('ta_morphometry', 20, env = env)

And compute with all the defaults:

rsaga.geoprocessor(
  'ta_morphometry', 20, 
  list(
    DEM='terrain/input_dsm/dsm.sgrd', 
    TEXTURE='terrain/out_products/textu.sgrd'
  ),
  env = env
)

Hydrology module

Again I will access the codes for the tools to get the usage:

rsaga.get.modules('ta_hydrology', env = env) %>% knitr::kable()
code name interactive
0 Flow Accumulation (Top-Down) FALSE
1 Flow Accumulation (Recursive) FALSE
2 Flow Accumulation (Flow Tracing) FALSE
4 Upslope Area FALSE
6 Flow Path Length FALSE
7 Slope Length FALSE
10 Cell Balance FALSE
13 Edge Contamination FALSE
15 SAGA Wetness Index FALSE
16 Lake Flood FALSE
18 Flow Accumulation (Mass-Flux Method) FALSE
19 Flow Width and Specific Catchment Area FALSE
20 Topographic Wetness Index (TWI) FALSE
21 Stream Power Index FALSE
22 LS Factor FALSE
23 Melton Ruggedness Number FALSE
24 TCI Low FALSE
25 LS-Factor, Field Based FALSE
26 Slope Limited Flow Accumulation FALSE
27 Maximum Flow Path Length FALSE
28 Flow between fields FALSE
29 Flow Accumulation (Parallelizable) FALSE

Melton Ruggedness Index

Simple flow accumulation related index, calculated as difference between maximum and minimum elevation in catchment area divided by square root of catchment area size. The calculation is performed for each grid cell, therefore minimum elevation is same as elevation at cell’s position. Due to the discrete character of a single maximum elevation, flow calculation is simply done with Deterministic 8.

This tool has its own module, and will return one outcome, coded ‘mridx’. We get the usage:

rsaga.get.usage('ta_hydrology', 23, env = env)

And compute with all the defaults:

rsaga.geoprocessor(
  'ta_hydrology', 23, 
  list(
    DEM='terrain/input_dsm/dsm.sgrd', 
    MRN='terrain/out_products/mridx.sgrd'
  ),
  env = env
)

LS Factor

L is the slope length factor, representing the effect of slope length on erosion. It is the ratio of soil loss from the field slope length to that from a 72.6-foot (22.1-meter) length on the same soil type and gradient. Slope length is the distance from the origin of overland flow along its flow path to the location of either concentrated flow or deposition. S is the slope steepness. Represents the effect of slope steepness on erosion. Soil loss increases more rapidly with slope steepness than it does with slope length. L factor and S factor are usually considered together. LS factors = the slope length factor L computes the effect of slope length on erosion and the slope steepness factor S computes the effect of slope steepness on erosion. Values of both L and S equal 1 for the unit plot conditions of 72.6 ft. length and 9 percent steepness. Values of L and S are relative and represent how erodible the particular slope length and steepness is relative to the 72.6 ft long, 9% steep unit plot. Thus some values of L and S are less than 1 and some values are greater than 1.

This particular tool I had to compute using the GUI for SAGA, because RSAGA does not let me use the LS Factor (one step) library that I need to do it right. In the GUI I only need to give the DEM. It is saved as ‘lsfct’.

This tool has its own module, and will return one outcome, coded ‘lsfct’. We get the usage:

rsaga.get.usage('terrain_analysis','LS Factor (One Step)', env = env)

And compute:

rsaga.geoprocessor(
  'terrain_analysis',
  'LS Factor (One Step)', 
  list(
    DEM='terrain/input_dsm/dsm.sgrd',
    LS_FACTOR='terrain/out_products/lsfct.sgrd',
    LS_METHOD=0,
    PREPROCESSING=2,
    MINSLOPE=0.0001
  ),
  env = env
)

SAGA Wetness Index

The ‘SAGA Wetness Index’ is, as the name says, similar to the ‘Topographic Wetness Index’ (TWI), but it is based on a modified catchment area calculation (‘Modified Catchment Area’), which does not think of the flow as very thin film. As result it predicts for cells situated in valley floors with a small vertical distance to a channel a more realistic, higher potential soil moisture compared to the standard TWI calculation.

This tool has its own module, and will return one outcome, coded ‘sagaw’. We get the usage:

rsaga.get.usage('ta_hydrology', 15, env = env)

And compute with defaults:

rsaga.geoprocessor(
  'ta_hydrology', 15, 
  list(
    DEM='terrain/input_dsm/dsm.sgrd', 
    TWI='terrain/out_products/sagaw.sgrd'
  ),
  env = env
)

Slope Length

A measurement of the distance from the origin of overland flow along its flow path to the location of either concentrated flow or deposition. 4

This tool has its own module, and will return one outcome, coded ‘sllgt’. We get the usage:

rsaga.get.usage('ta_hydrology', 7, env = env)

And compute with defaults:

rsaga.geoprocessor(
  'ta_hydrology', 7, 
  list(
    DEM='terrain/input_dsm/dsm.sgrd', 
    LENGTH='terrain/out_products/sllgt.sgrd'
  ),
  env = env
)

Stream Power Index

The Stream Power Index (SPI) is a measure of the erosive power of flowing water. SPI is calculated based upon slope and contributing area. SPI approximates locations where gullies might be more likely to form on the landscape.

To compute this index (spidx), some previous steps are required, i.e. computing the Specific Catchment Area (spcar). To do this, we use the Flow Accumulation (One Step) on the ta_hidrology module. This will also generate a flow accumulation layer (flow) that will be used later for the Vertical Distance to Channel Network.

rsaga.get.usage('terrain_analysis','Flow Accumulation (One Step)', env = env)

rsaga.geoprocessor(
  'terrain_analysis',
  'Flow Accumulation (One Step)',
  list(
    DEM='terrain/input_dsm/dsm.sgrd', 
    TCA='terrain/int_products/flow.sgrd',
    SCA='terrain/int_products/spcar.sgrd',
    PREPROCESSING=0,
    FLOW_ROUTING=0
  ),
  env = env
)

rsaga.get.usage('ta_hydrology', 21, env = env)

rsaga.geoprocessor(
  'ta_hydrology', 21,
  list(
    SLOPE='terrain/out_products/slope.sgrd',
    AREA='terrain/int_products/spcar.sgrd',
    SPI='terrain/out_products/spidx.sgrd'
  ),
  env = env
)

Topographic Wetness Index

The tool has its own module as Topographic Wetness Index (One Step). To get the usage:

rsaga.get.usage('terrain_analysis', 'Topographic Wetness Index (One Step)', env = env)

To compute we run the code below. I selected Deterministic 8 [0] for the Flow Distribution. It is coded ‘twidx’.

rsaga.geoprocessor(
  'terrain_analysis',
  'Topographic Wetness Index (One Step)',
  list(
    DEM='terrain/input_dsm/dsm.sgrd',
    TWI='terrain/out_products/twidx.sgrd', 
    FLOW_METHOD=0
  ),
  env = env
)

Lighting module

Again I will access the codes for the tools to get the usage:

rsaga.get.modules('ta_lighting', env = env) %>% knitr::kable()
code name interactive
0 Analytical Hillshading FALSE
2 Potential Incoming Solar Radiation FALSE
3 Sky View Factor FALSE
4 Topographic Correction FALSE
5 Topographic Openness FALSE
6 Visibility (points) FALSE
7 Potential Annual Insolation FALSE
8 Geomorphons FALSE

Hillshade

From this tool we will get the hillshade ‘shade’.

rsaga.geoprocessor(
  'ta_lighting', 0, 
  list(
    ELEVATION='terrain/input_dsm/dsm.sgrd',
    SHADE='terrain/out_products/shade.sgrd'
  ),
  env = env
)

Sky View Factor

Crucial variable widely used to quantify the characteristics of surface structures and estimate surface radiation budget. The SVF expresses the proportion (ratio) of radiation leaving the sky, assumed isotropic, that is able to reach a ground surface tilted at an arbitrary angle. Its value must vary between the minimum of 0, when the sky is not visible at all and to the maximum of 1, when the ground surface is horizontal and the sky entirely visible.

For this and the next tool, a multiscale parameter is chosen to speed up the computation. From this tool we can get two derivatives:

  • Sky view factor (svfct) - [not simplified]
  • Visible sky (visky)
rsaga.get.usage('ta_lighting', 3, env = env)

And compute with defaults:

rsaga.geoprocessor(
  'ta_lighting', 3, 
  list(
    DEM='terrain/input_dsm/dsm.sgrd', 
    VISIBLE='terrain/out_products/visky.sgrd',
    SVF='terrain/out_products/svfct.sgrd',
    METHOD=1,
    DLEVEL=3
  ),
  env = env
)

Topographic Openness

Topographic openness expresses the dominance (positive) or enclosure (negative) of a landscape location. Openness has been related to how wide a landscape can be viewed from any position. It has been proven to be a meaningful input for computer aided geomorphological mapping. Openness is an angular measure of the relation between surface relief and horizontal distance. For angles less than 90”, it is equivalent to the internal angle of a cone, its apex at a DEM location, constrained by neighboring elevations within a specified radial distance. Openness incorporates the terrain line-of-sight, or viewshed, concept and is calculated from multiple zenith and nadir angles-here along eight azimuths. Openness has two viewer perspectives. Positive values, expressing openness above the surface, are high for convex forms, whereas negative values describe this attribute below the surface and are high for concave forms. Openness values are mapped by gray-scale tones. The emphasis of terrain convexity and concavity in openness maps facilitates the interpretation of landforms on the Earth’s surface and its seafloor, and on the planets, as well as features on any irregular surface-such as those generated by industrial procedures.

From this tool we can get two derivatives:

  • Positive openness (posop)
  • Negative openness (negop)
rsaga.get.usage('ta_lighting', 5, env = env)

And compute with defaults:

rsaga.geoprocessor(
  'ta_lighting', 5, 
  list(
    DEM='terrain/input_dsm/dsm.sgrd', 
    POS='terrain/out_products/posop.sgrd',
    NEG='terrain/out_products/negop.sgrd',
    METHOD=0,
    DLEVEL=3
  ),
  env = env
)

Channels module

Vertical Distance to Channel Network

For this some previous steps are needed, see the complete code. The flow accumulation was already computed in the Stream Power Index step.

rsaga.get.usage('ta_channels', 0, env = env)
rsaga.geoprocessor(
  'ta_channels', 0, 
  list(
    ELEVATION='terrain/input_dsm/dsm.sgrd', 
    CHNLNTWRK='terrain/int_products/chnet.sgrd', 
    INIT_GRID='terrain/int_products/flow.sgrd', 
    INIT_VALUE=1000000
  ),
  env = env
)

rsaga.get.usage('ta_channels', 3, env = env)
rsaga.geoprocessor(
  'ta_channels', 3, 
  list(
    ELEVATION='terrain/input_dsm/dsm.sgrd',
    CHANNELS='terrain/int_products/chnet.sgrd',
    DISTANCE='terrain/out_products/vdcnw.sgrd'
  ),
  env = env
)

Final steps

Convert to TIFF

Useful function to convert to .tif extension.

library(gdalUtils)
library(stringr)

dir_path_to_translate = "./terrain/out_products/"
files_short = list.files(path = dir_path_to_translate, pattern = ".sdat$", full.names = F)
files_as_tif = str_replace(files_short, ".sdat$", ".tif")
existing_files = c(
  list.files(
    path = "./terrain/derivatives", 
    pattern = ".tif$", 
    full.names = F, 
    recursive = T
  ) %>% strex::str_after_first('/'),
  list.files(
    path = "./terrain/derivatives", 
    pattern = ".tif$", 
    full.names = F
  )
)

existing_files = existing_files[!is.na(existing_files)]

'%!in%' = function(x,y)!('%in%'(x,y))

files_to_translate = files_as_tif[files_as_tif %!in% existing_files] %>%
  str_replace(".tif", '.sdat')

files_for_translation = file.path(paste0(dir_path_to_translate,files_to_translate))

batch_gdal_translate(
  infiles = files_for_translation,
  outdir = "./terrain/derivatives",
  outsuffix = ".tif"
)

Define projection

Finally, there is a need to have every input for eCognition on the same CRS. For some reason, eCognition does not recognize this when done with GDAL. Hence, a Model Builder in ArcGIS was prepared to quickly transform everything to EPSG:2193, which is recognized and avoids conflicts. To run this, refer to the projection_tools.tbx on the ‘toolbox’ folder of the project.

References

Eisank, C., Hölbling, D., & Friedl, B. (2014). How well do terrain objects derived from pre-event DEM spatially correspond to landslides? Geological Society of America Abstracts with Programs, 46(6), 105. Vancouver, Canada.

Watkins, Russell, L., 2015, Terrain Metrics and Landscape Characterization from Bathymetric Data: SAGA GIS Methods and Command Sequences, Report prepared for the Ecospatial Information Team, Coral Reef Ecosystem Division, Pacific Islands Fisheries Science Center, Honolulu, HI, under NOAA contract number WE-133F-15-SE-0518, 46pp. ftp://ftp.soest.hawaii.edu/pibhmc/website/webdocs/documentation/linkages_project_methods_final.pdf