Downloading SRTM data with raster package?

3.2k views Asked by At

I'm trying to get SRTM data with "raster" package in R, but as soon as I'm choosing SRTM in getData command, I would get the following error:

library(raster)

srtm <- getData('SRTM', lon=16, lat=48)
trying URL 'ftp://xftp.jrc.it/pub/srtmV4/tiff/srtm_40_03.zip'
trying URL 'http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/srtm_40_03.ZIP'
downloaded 572 bytes

Error in .SRTM(..., download = download, path = path) : file not found
In addition: Warning messages:
1: In utils::download.file(url = aurl, destfile = fn, method = "auto",  :
  URL 'ftp://xftp.jrc.it/pub/srtmV4/tiff/srtm_40_03.zip': status was 'Couldn't resolve host name'
2: In utils::unzip(zipfilename, exdir = dirname(zipfilename)) :
  error 1 in extracting from zip file

Any Idea what is this error for ?

4

There are 4 answers

0
Dorian Grv On

I got all the same errors and I found a solution using httr package to download it (source here).

I tried BUT THIS DID NOT WORK:

url <- "https://srtm.csi.cgiar.org/wp-content/uploads/files/srtm_5x5/TIFF/srtm_37_04.zip"

library(RCurl)
url2 <- getURL(url)

download.file(url, "test", mode = "auto", method = "curl")
download.file(url, "test", mode = "wb", method = "curl")
download.file(url, "test")
# ... and so on 

library(data.table)
fread(url)

This worked:

library(httr)
httr::set_config(httr::config(ssl_verifypeer=0L))
GET(url, httr::write_disk(path = basename(url), overwrite = TRUE))

I needed to change the raster .download function for this. I could make definitive changes with reassignInPackage from R.utils (I think it is definitive) (reassignInPackage(name=".download", pkgName="raster", value="my.fn")) but I prefer a temporary change.

Place this in your code and it will fix the getData function:

y.fn <- function(aurl, filename){
  cat("You wanna download: ", aurl, "\n")
  cat("You wanna save it there : ", filename, "\n\n")
  httr::set_config(httr::config(ssl_verifypeer=0L))
  httr::GET(aurl, httr::write_disk(path = filename, overwrite = TRUE))
}
tmpfun <- get(".download", envir = asNamespace("raster"))
environment(my.fn) <- environment(tmpfun)
attributes(my.fn) <- attributes(tmpfun)  # don't know if this is really needed
assignInNamespace(".download", my.fn, ns="raster")

and try again

4
SamAct On

I have the same problem, it seems to be a bug. The getData function in raster package checks for availability of the raster file in three different url's.

1. ftp://xftp.jrc.it/pub/srtmV4/tiff/FILENAME
2. http://hypersphere.telascience.org/elevation/cgiar_srtm_v4/tiff/zip/FILENAME
3. http://srtm.csi.cgiar.org/SRT-ZIP/SRTM_V41/SRTM_Data_GeoTiff/FILENAME

The first two of them (as of today) are not working or cannot be accessible. However for some reason a small bit data is getting transferred across the server, so the package assumes it to be a available file only to reach an error by utils. The third url however is most trusted one among the three.

I did some digging and came up with the following function after slightly modifying the raster package itself so that it uses the third url. You can input Longitude and Latitude values here. Note that this is only useful if you want to download the files based on Latitude & Longitude.

SRTM<-function(lon, lat) {
  stopifnot(lon >= -180 & lon <= 180)
  stopifnot(lat >= -60 & lat <= 60)
  rs <- raster(nrows=24, ncols=72, xmn=-180, xmx=180, ymn=-60, ymx=60 )
  rowTile <- rowFromY(rs, lat)
  colTile <- colFromX(rs, lon)
  if (rowTile < 10) { rowTile <- paste('0', rowTile, sep='') }
  if (colTile < 10) { colTile <- paste('0', colTile, sep='') }

  f <- paste('srtm_', colTile, '_', rowTile, sep="")
  theurl <- paste("http://srtm.csi.cgiar.org/wp-content/uploads/files/srtm_5x5/TIFF/", f, ".ZIP", sep="")
  utils::download.file(url=theurl, destfile='srtm_40_0.zip', method="auto", quiet = FALSE, mode = "wb", cacheOK = TRUE)
}

Example:

SRTM(lon=16, lat=48)

This will result in a file named srtm_40_03.zip in your folder which would normally contain a tif, a hdr and a tfw file of the same name. Use them for further process as usual.

EDIT DATE 22-JAN-19: The srtm link as changed (as well), the above code has been adapted to reflect this.

0
pokyah On

I had the exact same error while trying to downldoad SRTM data using raster::getData(). As mentioned by samAct, the problem is related to the URL's that are not accessible anymore.

My solution was to edit the getData function so that it tries first the http://srtm.csi.cgiar.org/SRT-ZIP/SRTM_V41/SRTM_Data_GeoTiff/FILENAME URL.

To use my edited version of the raster package simply use `devtools::install_github("pokyah/raster"). This will overwrite your current version and make the getData work with the valid URL.

devtools::install_github("pokyah/raster")
library(raster)

Then, you can use this function to download the SRTM data for your region of interest :

# @param country_code.chr a character specifying the ISO contrycode. Ex : BE for belgium
# @param NAME_1.chr a character specifying the NAME_1 value for lower than country level information
# @param aggregation_factor.num a numeric specifying the aggregation factor to get the desired spatial resolution
# @param EPSG.chr a character specifying the EPSG code of the desired Coordiante Reference System (CRS)
# @param path.chr a character specifying the path where to dowload the SRTM data

build_highRes_terrain_rasters.fun <- function(country_code.chr, NAME_1.chr=NULL, aggregation_factor.num=NULL, EPSG.chr=NULL, path.chr) {
  # Path to downloaded SRTM Tiles refs
  srtm.tiles.ref <- raster::shapefile("<PATH_TO_DOWNLOADED_TILES_REFS")

  # Get country geometry first
  extent.sp <- raster::getData('GADM', country=country_code.chr, level=1)

  if(!is.null(NAME_1.chr)){
    extent.sp <- subset(extent.sp, NAME_1 == NAME_1.chr)
  }

  # Intersect extent geometry and tile grid
  intersects <- rgeos::gIntersects(extent.sp, srtm.tiles.ref, byid=T)
  tiles      <- srtm.tiles.ref[intersects[,1],]

  # Download tiles using getData
  # inspired from https://www.gis-blog.com/download-srtm-for-an-entire-country/
  srtm_list  <- list()
  for(i in 1:length(tiles)) {
    lon <- extent(tiles[i,])[1]  + (extent(tiles[i,])[2] - extent(tiles[i,])[1]) / 2
    lat <- extent(tiles[i,])[3]  + (extent(tiles[i,])[4] - extent(tiles[i,])[3]) / 2

    tile <- getData('SRTM', #data are downloaded from http://www.cgiar-csi.org/. See getData do of pokyah/raster repo on github
                    lon=lon,
                    lat=lat,
                    download = FALSE,
                    path = path.chr)

    srtm_list[[i]] <- tile
  }

  # Mosaic tiles
  srtm_list$fun <- mean
  srtm_mosaic.ras <- do.call(raster::mosaic, srtm_list)

  # Crop tiles to extent borders
  extent.elevation.ras <- raster::crop(srtm_mosaic.ras, extent.sp)
  extent.elevation.ras <- raster::mask(extent.elevation.ras, extent.sp)

  # transform to desired CRS
  if(!is.null(EPSG.chr)){
    raster::projectRaster(extent.elevation.ras, crs = toString((dplyr::filter(rgdal::make_EPSG(), code==EPSG.chr))$prj4))
  }

  # aggregate to lower resolution
  # inspired from https://stackoverflow.com/questions/32278825/how-to-change-the-resolution-of-a-raster-layer-in-r
  if(!is.null(aggregation_factor.num)){
    extent.elevation.ras <- raster::aggregate(extent.elevation.ras, fact=aggregation_factor.num)
  }

  # compute the slope from the elevation
  # inspired from https://rpubs.com/etiennebr/visualraster
  extent.slope.ras <- raster::terrain(extent.elevation.ras, opt="slope", unit="degrees")
  extent.aspect.ras <- raster::terrain(extent.elevation.ras, opt="aspect", unit="degrees")
  extent.roughness.ras <- raster::terrain(extent.elevation.ras, opt="roughness")

  # compute the aspect from the elevation
  extent.terrain.ras = raster::stack(
    extent.elevation.ras,
    extent.slope.ras,
    extent.aspect.ras,
    extent.roughness.ras)
}

hope it helps !

1
FedRo On

today, 21-01-2019, the link was still broken, even the one corrected by pokyah. New working version at:

devtools::install_github("fedefyco/raster")
library(raster)