Skip to content

Commit e0f8133

Browse files
Issue81 catch errors (#89)
* Add further error handling for downloads * error when single point on geom with no extent is used to as aoi. * test error on single geom * update download function in band mapping * version bump * remove pointless x from error statement * band mapping updates * add suffix for dduplicated date times (relevant for s2 images). * Apply suggestions from code review --------- Co-authored-by: Michael Mahoney <[email protected]>
1 parent ed27ab3 commit e0f8133

10 files changed

+95
-39
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: rsi
22
Title: Efficiently Retrieve and Process Satellite Imagery
3-
Version: 0.3.1.9000
3+
Version: 0.3.2
44
Authors@R: c(
55
person("Michael", "Mahoney", , "[email protected]", role = c("aut", "cre"),
66
comment = c(ORCID = "0000-0003-2402-304X")),

NEWS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# rsi (development version)
22

3+
* Failed downloads and merges should now be handled a bit better. Thanks
4+
to @h-a-graham for #89 and to @lucas-johnson for #81.
5+
6+
* If `composite = NULL` and the resource has duplicated asset timestamps,
7+
`get_stac_data()` will now generate unique filenames (rather than saving
8+
multiple files to the same path). Thanks to @h-a-graham for #89 and #90.
9+
310
# rsi 0.3.1
411

512
* A test that requires online resources is now skipped on CRAN. There are

R/download.R

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,31 @@ rsi_download_rasters <- function(items,
128128
)
129129
},
130130
error = function(e) {
131-
rlang::warn(
132-
glue::glue(
133-
"Failed to download {items$features[[which_item]]$id %||% 'UNKNOWN'} from {items$features[[which_item]]$properties$datetime %||% 'UNKNOWN'}" # nolint
131+
# stop if failure occurs when merging.
132+
if (merge) {
133+
rlang::abort(
134+
glue::glue(
135+
"GDAL warp failed when attempting to merge ",
136+
"{length(unlist(feature_iter))} items"
137+
),
138+
class = "rsi_download_warp_error", parent = e
134139
)
140+
}
141+
142+
expr1 <- items$features[[which_item]]$id %||% "UNKNOWN"
143+
expr2 <- items$features[[which_item]]$properties$datetime %||% "UNKNOWN"
144+
145+
err_msg <- glue::glue(
146+
"Failed to download {expr1} from {expr2}" # nolint
135147
)
148+
149+
# stop if failure occurs when there is only one item to download.
150+
if (length(feature_iter) == 1) {
151+
rlang::abort(err_msg, class = "rsi_download_warp_error", parent = e)
152+
}
153+
154+
# warn if failure occurs when multiple items are being downloaded.
155+
rlang::warn(err_msg, parent = e)
136156
download_locations[which_item, ] <<- NA
137157
}
138158
)

R/get_stac_data.R

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@
134134
#' (i.e., to aggregate pixel values from multiple images into a single value).
135135
#' Options include "merge", which 'stamps' images on top of one another such that
136136
#' the "last" value downloaded for a pixel -- which isn't guaranteed to be the most
137-
#' recent one -- will be the only value used, or any of "sum", "mean", "median",
137+
#' recent one -- will be the only value used, or any of "sum", "mean", "median",
138138
#' "min", or "max", which consider all values available at each pixel.
139139
#' Set to `NULL` to not composite
140140
#' (i.e., to rescale and save each individual file independently).
@@ -143,7 +143,7 @@
143143
#' argument of [sf::gdal_utils()]. The same set of options are used for all
144144
#' downloaded data and the final output images; this means that some common
145145
#' options (for instance, `PREDICTOR=3`) may cause errors if bands are of
146-
#' varying data types. The default values are provided by
146+
#' varying data types. The default values are provided by
147147
#' [rsi_gdalwarp_options()].
148148
#' @param gdal_config_options Options passed to `gdalwarp` through the
149149
#' `config_options` argument of [sf::gdal_utils()]. The default values are
@@ -186,13 +186,13 @@
186186
#' end_date = "2022-08-30",
187187
#' output_filename = tempfile(fileext = ".tif")
188188
#' )
189-
#'
190-
#' landsat_image |>
189+
#'
190+
#' landsat_image |>
191191
#' terra::rast() |>
192192
#' terra::stretch() |>
193193
#' terra::plotRGB()
194-
#'
195-
#' # The `get_*_imagery()` functions will download
194+
#'
195+
#' # The `get_*_imagery()` functions will download
196196
#' # all available "data" assets by default
197197
#' # (usually including measured values, and excluding derived bands)
198198
#' sentinel1_data <- get_sentinel1_imagery(
@@ -202,17 +202,17 @@
202202
#' output_filename = tempfile(fileext = ".tif")
203203
#' )
204204
#' names(terra::rast(sentinel1_data))
205-
#'
205+
#'
206206
#' # You can see what bands will be downloaded by a function
207207
#' # by inspecting the corresponding `band_mapping` object:
208208
#' sentinel2_band_mapping$planetary_computer_v1
209-
#'
209+
#'
210210
#' # And you can add additional assets using `c()`:
211211
#' c(
212212
#' sentinel2_band_mapping$planetary_computer_v1,
213213
#' "scl"
214214
#' )
215-
#'
215+
#'
216216
#' # Or subset the assets downloaded using `[` or `[[`:
217217
#' sentinel2_imagery <- get_sentinel2_imagery(
218218
#' aoi,
@@ -222,7 +222,7 @@
222222
#' output_filename = tempfile(fileext = ".tif")
223223
#' )
224224
#' names(terra::rast(sentinel2_imagery))
225-
#'
225+
#'
226226
#' # If you're downloading data for a particularly large AOI,
227227
#' # and can't composite the resulting images or want to make
228228
#' # sure you can continue an interrupted download,
@@ -239,7 +239,7 @@
239239
#' )
240240
#' }
241241
#' )
242-
#' # You'll get a list of tiles that you can then composite or
242+
#' # You'll get a list of tiles that you can then composite or
243243
#' # work with however you wish:
244244
#' unlist(tiles)
245245
#'
@@ -273,6 +273,17 @@ get_stac_data <- function(aoi,
273273
)
274274
}
275275

276+
aoi_bbox <- sf::st_bbox(aoi)
277+
if (aoi_bbox$xmin == aoi_bbox$xmax | aoi_bbox$ymin == aoi_bbox$ymax) {
278+
rlang::abort(
279+
c(
280+
"`aoi` has no extent.",
281+
"i" = "This can occur when `aoi` is a single point geometry."
282+
),
283+
class = "rsi_aoi_is_point"
284+
)
285+
}
286+
276287
if (sf::st_is_longlat(aoi) && !(is.null(pixel_x_size) || is.null(pixel_y_size)) && all(c(pixel_x_size, pixel_y_size) %in% c(10, 30))) {
277288
rlang::warn(
278289
c(
@@ -360,13 +371,14 @@ get_stac_data <- function(aoi,
360371
if (is.null(asset_names)) {
361372
asset_names <- rstac::items_assets(items)
362373
if (length(asset_names) > 1) {
363-
rlang::warn(c(
364-
"`asset_names` was `NULL`, so rsi is attempting to download all assets in items in this collection.",
365-
i = "This includes multiple assets, so rsi is attempting to download all of them using the same download function.",
366-
i = "This might cause errors or not be what you want! Specify `asset_names` to fix this (and to silence this warning)."
367-
),
368-
class = "rsi_missing_asset_names"
369-
)
374+
rlang::warn(
375+
c(
376+
"`asset_names` was `NULL`, so rsi is attempting to download all assets in items in this collection.",
377+
i = "This includes multiple assets, so rsi is attempting to download all of them using the same download function.",
378+
i = "This might cause errors or not be what you want! Specify `asset_names` to fix this (and to silence this warning)."
379+
),
380+
class = "rsi_missing_asset_names"
381+
)
370382
}
371383
}
372384
if (is.null(names(asset_names))) names(asset_names) <- asset_names
@@ -412,6 +424,9 @@ get_stac_data <- function(aoi,
412424
if (!is.null(stats::na.action(download_results))) {
413425
items$features[stats::na.action(download_results)] <- NULL
414426
}
427+
428+
temp_ras_files <- unlist(download_results)
429+
on.exit(file.remove(temp_ras_files), add = TRUE)
415430
# mask
416431
if (!is.null(mask_band)) {
417432
download_results <- rsi_apply_masks(
@@ -440,10 +455,7 @@ get_stac_data <- function(aoi,
440455
lapply(download_results, rescale_band, scale_strings)
441456
}
442457

443-
on.exit(file.remove(unlist(download_results)), add = TRUE)
444-
445458
if (drop_mask_band) items_urls[[mask_band]] <- NULL
446-
447459
mapply(
448460
function(in_bands, vrt) {
449461
stack_rasters(
@@ -462,7 +474,8 @@ get_stac_data <- function(aoi,
462474
app <- tryCatch(rstac::items_datetime(items), error = function(e) NA)
463475
app <- gsub(":", "", app) # #29, #32
464476
if (any(is.na(app))) app <- NULL
465-
app <- app %||% seq_along(download_results)
477+
app <- app %||% as.character(seq_along(download_results))
478+
app <- make.unique(app, sep = "_")
466479

467480
output_filename <- paste0(
468481
tools::file_path_sans_ext(output_filename),
@@ -724,15 +737,17 @@ rsi_composite_bands <- function(download_locations,
724737
)
725738
)
726739
} else {
727-
do.call(
728-
terra::mosaic,
729-
list(
730-
x = terra::sprc(lapply(download_locations[[band_name]], terra::rast)),
731-
fun = composite_function,
732-
filename = out_file,
733-
overwrite = TRUE
740+
capture.output({
741+
do.call(
742+
terra::mosaic,
743+
list(
744+
x = terra::sprc(lapply(download_locations[[band_name]], terra::rast)),
745+
fun = composite_function,
746+
filename = out_file,
747+
overwrite = TRUE
748+
)
734749
)
735-
)
750+
})
736751
}
737752

738753
out_file
@@ -845,11 +860,12 @@ get_rescaling_formula <- function(items, band_name, element) {
845860
)
846861

847862
if (length(unique(elements)) != 1) {
848-
rlang::warn(c(
849-
glue::glue("Images in band {band_name} have different {element}s."),
850-
i = "Returning images without rescaling."
851-
),
852-
class = "rsi_multiple_scaling_formulas"
863+
rlang::warn(
864+
c(
865+
glue::glue("Images in band {band_name} have different {element}s."),
866+
i = "Returning images without rescaling."
867+
),
868+
class = "rsi_multiple_scaling_formulas"
853869
)
854870
elements <- NA_real_
855871
}

data/alos_palsar_band_mapping.rda

1.52 KB
Binary file not shown.

data/dem_band_mapping.rda

2.11 KB
Binary file not shown.

data/landsat_band_mapping.rda

1.96 KB
Binary file not shown.

data/sentinel1_band_mapping.rda

1.56 KB
Binary file not shown.

data/sentinel2_band_mapping.rda

2.05 KB
Binary file not shown.

tests/testthat/test-get_stac_data.R

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,3 +386,16 @@ test_that("Providing no asset names fires the expected warning", {
386386
)
387387
)
388388
})
389+
390+
test_that("Providing a single point geometry throws an error", {
391+
expect_error(
392+
get_landsat_imagery(
393+
aoi = sf::st_sfc(sf::st_point(c(-74.912131, 44.080410)), crs = 4326),
394+
start_date = "2022-06-01",
395+
end_date = "2022-08-01",
396+
composite_function = NULL,
397+
output_filename = tempfile(fileext = ".tif")
398+
),
399+
class = "rsi_aoi_is_point"
400+
)
401+
})

0 commit comments

Comments
 (0)