From 676d5371b6a16b333fcd6027dfaa3849bc2a3bd8 Mon Sep 17 00:00:00 2001 From: Jonas Vestby Date: Tue, 19 May 2026 07:38:42 +0200 Subject: [PATCH 1/7] functions now return better error messages --- R/build_priogrid.R | 123 ++++++++++++++++++++++++++-- R/config.R | 10 ++- R/data_SHDI.R | 10 +++ R/data_cshapes.R | 45 ++++++++++ R/data_side.R | 43 +++++++++- R/download_data.R | 199 ++++++++++++++++++++++++++++++++++++++------- 6 files changed, 392 insertions(+), 38 deletions(-) diff --git a/R/build_priogrid.R b/R/build_priogrid.R index 8001b2d..c9e6cfa 100644 --- a/R/build_priogrid.R +++ b/R/build_priogrid.R @@ -177,11 +177,43 @@ calc_pg <- function(varnames = NULL, overwrite = FALSE, config = pg_current_conf # Calculate variables message(paste("Variables to calculate:", paste(valid_varnames, collapse = ", "))) message(paste("Saving to:", save_to)) + failed_vars <- character(0) for (varname in valid_varnames) { message(paste("Calculating", varname)) - gen_fun <- get(paste0("gen_", varname)) - r <- gen_fun(config = config) - save_pgvariable(r, varname, save_to = save_to) + result <- tryCatch({ + gen_fun <- get(paste0("gen_", varname)) + r <- gen_fun(config = config) + save_pgvariable(r, varname, save_to = save_to) + NULL + }, error = function(e) { + is_file_error <- grepl( + "not found|does not exist|No such file|cannot open|missing files|No files in metadata", + conditionMessage(e), ignore.case = TRUE + ) + if (is_file_error) { + warning( + sprintf("Skipping '%s': a required source file is missing or unreadable.\n", varname), + " Error: ", conditionMessage(e), "\n", + " Check availability: pg_data_availability()\n", + " Download missing: download_pg_rawdata()", + call. = FALSE) + } else { + warning( + sprintf("Skipping '%s': computation failed.\n", varname), + " Error: ", conditionMessage(e), + call. = FALSE) + } + varname + }) + if (!is.null(result)) failed_vars <- c(failed_vars, result) + } + + if (length(failed_vars) > 0) { + message( + "calc_pg() completed with ", length(failed_vars), " failure(s): ", + paste(failed_vars, collapse = ", "), "\n", + "Succeeded: ", length(valid_varnames) - length(failed_vars), + " / ", length(valid_varnames)) } invisible(NULL) @@ -222,6 +254,24 @@ save_pgvariable <- function(rast, varname, save_to = pgout_path()) { } saveRDS(rast, filepath) + .pg_record_checksum(filepath, varname, save_to) + invisible(NULL) +} + +# Internal helper: record an MD5 checksum entry in _checksums.csv +.pg_record_checksum <- function(filepath, label, base_path) { + md5_val <- tools::md5sum(filepath) + checksum_file <- file.path(base_path, "_checksums.csv") + row <- data.frame(varname = label, filename = basename(filepath), md5 = md5_val, + recorded_at = as.character(Sys.time()), stringsAsFactors = FALSE) + if (file.exists(checksum_file)) { + existing <- utils::read.csv(checksum_file, stringsAsFactors = FALSE) + existing <- existing[existing$varname != label, ] + updated <- rbind(existing, row) + } else { + updated <- row + } + utils::write.csv(updated, checksum_file, row.names = FALSE) invisible(NULL) } @@ -271,7 +321,8 @@ load_pgvariable <- function(varname, version = NULL, type = "05deg_yearly", spatial_hash = NULL, - temporal_hash = NULL) { + temporal_hash = NULL, + verify_checksums = FALSE) { rlang::check_installed("terra", reason = "to load PRIO-GRID variable rasters") has_hashes <- !is.null(spatial_hash) && !is.null(temporal_hash) @@ -316,6 +367,26 @@ load_pgvariable <- function(varname, stop("Variable '", varname, "' not found at: ", filepath) } + if (isTRUE(verify_checksums)) { + cs_file <- file.path(dirname(filepath), "_checksums.csv") + if (file.exists(cs_file)) { + cs_df <- utils::read.csv(cs_file, stringsAsFactors = FALSE) + expected <- cs_df[cs_df$varname == varname, ] + if (nrow(expected) == 1) { + actual <- tools::md5sum(filepath) + if (actual != expected$md5) { + warning( + "Checksum mismatch for '", varname, "': the file may be corrupted.\n", + " Expected MD5: ", expected$md5, "\n", + " Actual MD5: ", actual, "\n", + " File: ", filepath, "\n", + " Recalculate with: calc_pg('", varname, "', overwrite = TRUE)", + call. = FALSE) + } + } + } + } + terra::unwrap(readRDS(filepath)) } @@ -465,7 +536,8 @@ read_pg_static <- function(config = NULL, temporal_hash = NULL, as_raster = FALSE, test = FALSE, - overwrite = FALSE) { + overwrite = FALSE, + verify_checksums = FALSE) { cfg <- resolve_pg_mode(config, version, type, spatial_hash, temporal_hash, overwrite) @@ -481,6 +553,24 @@ read_pg_static <- function(config = NULL, # Return cached if available (lightweight path — no terra needed) if (!as_raster && !test && file.exists(fname) && !cfg$overwrite) { + if (isTRUE(verify_checksums)) { + cs_file <- file.path(cfg$base_path, "_checksums.csv") + if (file.exists(cs_file)) { + cs_df <- utils::read.csv(cs_file, stringsAsFactors = FALSE) + expected <- cs_df[cs_df$varname == "pg_static.parquet", ] + if (nrow(expected) == 1) { + actual <- tools::md5sum(fname) + if (actual != expected$md5) { + warning( + "Checksum mismatch for cached 'pg_static.parquet': the file may be corrupted.\n", + " Expected MD5: ", expected$md5, "\n", + " Actual MD5: ", actual, "\n", + " Rebuild with: read_pg_static(overwrite = TRUE)", + call. = FALSE) + } + } + } + } return(nanoparquet::read_parquet(fname)) } @@ -533,6 +623,7 @@ read_pg_static <- function(config = NULL, # Save to cache rlang::check_installed("arrow", reason = "to write parquet files") arrow::write_parquet(df, fname) + .pg_record_checksum(fname, "pg_static.parquet", cfg$base_path) return(df) } @@ -582,7 +673,8 @@ read_pg_timevarying <- function(config = NULL, temporal_hash = NULL, as_raster = FALSE, test = FALSE, - overwrite = FALSE) { + overwrite = FALSE, + verify_checksums = FALSE) { cfg <- resolve_pg_mode(config, version, type, spatial_hash, temporal_hash, overwrite) @@ -598,6 +690,24 @@ read_pg_timevarying <- function(config = NULL, # Return cached if available (lightweight path — no terra needed) if (!as_raster && !test && file.exists(fname) && !cfg$overwrite) { + if (isTRUE(verify_checksums)) { + cs_file <- file.path(cfg$base_path, "_checksums.csv") + if (file.exists(cs_file)) { + cs_df <- utils::read.csv(cs_file, stringsAsFactors = FALSE) + expected <- cs_df[cs_df$varname == "pg_timevarying.parquet", ] + if (nrow(expected) == 1) { + actual <- tools::md5sum(fname) + if (actual != expected$md5) { + warning( + "Checksum mismatch for cached 'pg_timevarying.parquet': the file may be corrupted.\n", + " Expected MD5: ", expected$md5, "\n", + " Actual MD5: ", actual, "\n", + " Rebuild with: read_pg_timevarying(overwrite = TRUE)", + call. = FALSE) + } + } + } + } return(nanoparquet::read_parquet(fname)) } @@ -669,6 +779,7 @@ read_pg_timevarying <- function(config = NULL, compress = "gzip") rlang::check_installed("arrow", reason = "to write parquet files") arrow::write_parquet(df, fname) + .pg_record_checksum(fname, "pg_timevarying.parquet", cfg$base_path) return(df) } diff --git a/R/config.R b/R/config.R index 4b71d73..f2b1d23 100644 --- a/R/config.R +++ b/R/config.R @@ -35,7 +35,8 @@ pg_config <- function(nrow = 360L, start_date = as.Date("1850-12-31"), end_date = Sys.Date(), verbose = TRUE, - automatic_download = TRUE) { + automatic_download = TRUE, + verify_checksums = FALSE) { if (!is.numeric(extent) || length(extent) != 4) stop("extent must be a numeric vector of length 4") @@ -48,7 +49,8 @@ pg_config <- function(nrow = 360L, start_date = as.Date(start_date), end_date = if (identical(end_date, "today")) Sys.Date() else as.Date(end_date), verbose = as.logical(verbose), - automatic_download = as.logical(automatic_download) + automatic_download = as.logical(automatic_download), + verify_checksums = as.logical(verify_checksums) ) validate_pg_config(cfg) @@ -87,7 +89,8 @@ pg_set_config <- function(...) { updates <- list(...) valid_fields <- c("nrow", "ncol", "crs", "extent", "temporal_resolution", - "start_date", "end_date", "verbose", "automatic_download") + "start_date", "end_date", "verbose", "automatic_download", + "verify_checksums") invalid <- setdiff(names(updates), valid_fields) if (length(invalid) > 0) { stop("Unknown config fields: ", paste(invalid, collapse = ", "), @@ -237,6 +240,7 @@ validate_pg_config <- function(cfg) { if (!inherits(cfg$end_date, "Date")) stop("end_date must be a Date") if (!is.logical(cfg$verbose) || is.na(cfg$verbose)) stop("verbose must be logical") if (!is.logical(cfg$automatic_download) || is.na(cfg$automatic_download)) stop("automatic_download must be logical") + if (!is.logical(cfg$verify_checksums) || is.na(cfg$verify_checksums)) stop("verify_checksums must be logical") invisible(NULL) } diff --git a/R/data_SHDI.R b/R/data_SHDI.R index a8085e3..aa1bd25 100644 --- a/R/data_SHDI.R +++ b/R/data_SHDI.R @@ -296,6 +296,16 @@ shdi <- function(variable = "shdi", config = pg_current_config()) { pg_years <- lubridate::year(pg_dates(config)) shdi_years <- pg_years[pg_years %in% unique(df$year)] + if (length(shdi_years) == 0) { + warning( + "shdi(): config date range [", config$start_date, " to ", config$end_date, + "] does not overlap SHDI data coverage (years ", + min(unique(df$year)), " to ", max(unique(df$year)), ").\n", + " Returning empty SpatRaster. Adjust config$start_date / config$end_date.", + call. = FALSE) + return(terra::rast()) + } + for(t in 1:length(shdi_years)){ out <- df |> dplyr::filter(year == shdi_years[t]) pg <- prio_blank_grid(config) diff --git a/R/data_cshapes.R b/R/data_cshapes.R index c1fb906..e5a7c2e 100644 --- a/R/data_cshapes.R +++ b/R/data_cshapes.R @@ -227,6 +227,15 @@ gen_cshapes_cover_share <- function(cshp = read_cshapes(), config = pg_current_c temporal_interval <- lubridate::interval(min(cshp$gwsdate), max(cshp$gwedate)) time_slices <- time_slices[time_slices %within% temporal_interval] + if (length(time_slices) == 0) { + warning( + "gen_cshapes_cover_share(): config date range [", config$start_date, " to ", config$end_date, + "] does not overlap CShapes coverage [", min(cshp$gwsdate), " to ", max(cshp$gwedate), "].\n", + " Returning empty SpatRaster. Adjust config$start_date / config$end_date.", + call. = FALSE) + return(terra::rast()) + } + r <- cshapes_cover_share(time_slices[1], cshp = cshp, config = config) for(i in 2:length(time_slices)){ t <- time_slices[i] @@ -318,6 +327,15 @@ gen_cshapes_gwcode <- function(cshp = read_cshapes(), config = pg_current_config temporal_interval <- lubridate::interval(min(cshp$gwsdate), max(cshp$gwedate)) time_slices <- time_slices[time_slices %within% temporal_interval] + if (length(time_slices) == 0) { + warning( + "gen_cshapes_gwcode(): config date range [", config$start_date, " to ", config$end_date, + "] does not overlap CShapes coverage [", min(cshp$gwsdate), " to ", max(cshp$gwedate), "].\n", + " Returning empty SpatRaster. Adjust config$start_date / config$end_date.", + call. = FALSE) + return(terra::rast()) + } + r <- cshapes_gwcode(time_slices[1], cshp = cshp, config = config) for(i in 2:length(time_slices)){ t <- time_slices[i] @@ -471,6 +489,15 @@ gen_bdist1 <- function(cshp = read_cshapes(), config = pg_current_config(), geod time_slices <- pg_dates(config) time_slices <- time_slices[time_slices %within% temporal_interval] + if (length(time_slices) == 0) { + warning( + "gen_bdist1(): config date range [", config$start_date, " to ", config$end_date, + "] does not overlap CShapes coverage [", min(cshp$gwsdate), " to ", max(cshp$gwedate), "].\n", + " Returning empty SpatRaster. Adjust config$start_date / config$end_date.", + call. = FALSE) + return(terra::rast()) + } + res <- bdist1(time_slices[1], cshp = cshp, config = config, geodesic = geodesic) r <- res$bdist1 for(i in 2:length(time_slices)){ @@ -635,6 +662,15 @@ gen_bdist2 <- function(cshp = read_cshapes(), config = pg_current_config()){ time_slices <- pg_dates(config) time_slices <- time_slices[time_slices %within% temporal_interval] + if (length(time_slices) == 0) { + warning( + "gen_bdist2(): config date range [", config$start_date, " to ", config$end_date, + "] does not overlap CShapes coverage [", min(cshp$gwsdate), " to ", max(cshp$gwedate), "].\n", + " Returning empty SpatRaster. Adjust config$start_date / config$end_date.", + call. = FALSE) + return(terra::rast()) + } + res <- bdist2(time_slices[1], cshp = cshp, config = config) r <- res$bdist2 for(i in 2:length(time_slices)){ @@ -787,6 +823,15 @@ gen_bdist3 <- function(cshp = read_cshapes(), config = pg_current_config(), geod time_slices <- pg_dates(config) time_slices <- time_slices[time_slices %within% temporal_interval] + if (length(time_slices) == 0) { + warning( + "gen_bdist3(): config date range [", config$start_date, " to ", config$end_date, + "] does not overlap CShapes coverage [", min(cshp$gwsdate), " to ", max(cshp$gwedate), "].\n", + " Returning empty SpatRaster. Adjust config$start_date / config$end_date.", + call. = FALSE) + return(terra::rast()) + } + res <- bdist3(time_slices[1], cshp = cshp, config = config, geodesic = geodesic) r <- res$bdist3 for(i in 2:length(time_slices)){ diff --git a/R/data_side.R b/R/data_side.R index e646bfb..df02e83 100644 --- a/R/data_side.R +++ b/R/data_side.R @@ -29,7 +29,37 @@ read_side <- function() { side_meta_file <- files[grepl("side.metadata.df.RData", files)] files <- files[!grepl("side.metadata.df.RData", files)] - load(side_meta_file) + if (length(side_meta_file) == 0) { + stop( + "Expected 'side.metadata.df.RData' was not found among the SIDE source files.\n", + " Files returned: ", paste(basename(files), collapse = ", "), "\n", + " Re-download: download_pg_rawdata(file_info = pg_rawfiles() |> dplyr::filter(source_name == 'ETH SIDE'))", + call. = FALSE) + } + + side_load_env <- new.env(parent = emptyenv()) + tryCatch( + load(side_meta_file, envir = side_load_env), + error = function(e) stop( + "Failed to load SIDE metadata file: ", side_meta_file, "\n", + " The file may be corrupted. Original error: ", conditionMessage(e), "\n", + " Re-download with overwrite=TRUE: download_pg_rawdata(file_info = pg_rawfiles() |> dplyr::filter(source_name == 'ETH SIDE'), overwrite = TRUE)", + call. = FALSE) + ) + if (!exists("side.metadata.df", envir = side_load_env)) { + stop( + "'side.metadata.df' not found in loaded RData file. Objects present: ", + paste(ls(side_load_env), collapse = ", "), "\n", + " The file may be a different version. Contact the PRIO-GRID administrators.", + call. = FALSE) + } + side.metadata.df <- side_load_env$side.metadata.df + required_cols <- c("sideid", "marker", "country", "groupname") + missing_cols <- setdiff(required_cols, names(side.metadata.df)) + if (length(missing_cols) > 0) { + stop("'side.metadata.df' is missing expected columns: ", + paste(missing_cols, collapse = ", "), call. = FALSE) + } side_meta <- side.metadata.df |> dplyr::filter(marker == "ethnic") |> @@ -265,6 +295,17 @@ side <- function(status = c("excluded", "included", "irrelevant"), config = pg_c measurement_dates <- pg_dates(config) years_needed <- sort(unique(lubridate::year(measurement_dates))) years_needed <- years_needed[years_needed %in% unique(status_matches$year)] + + if (length(years_needed) == 0) { + warning( + "side(): config date range [", config$start_date, " to ", config$end_date, + "] does not overlap available SIDE match years for status '", status, "' (", + min(status_matches$year), " to ", max(status_matches$year), ").\n", + " Returning empty SpatRaster. Adjust config$start_date / config$end_date.", + call. = FALSE) + return(terra::rast()) + } + surfaces <- .side_prepare_group_surfaces(side$meta, status_matches) annual_layers <- vector("list", length(years_needed)) diff --git a/R/download_data.R b/R/download_data.R index 58ffe7b..862f7d9 100644 --- a/R/download_data.R +++ b/R/download_data.R @@ -88,29 +88,60 @@ pg_rawfiles <- function(use_mirror = TRUE, only_file_extensions = FALSE){ #' #' @examples #' res <- check_pgsourcefiles() -check_pgsourcefiles <- function(){ +check_pgsourcefiles <- function(verbose = TRUE){ destfolder <- pg_rawfolder() file_info <- pg_rawfiles() lacking_pgchecksum <- dplyr::anti_join(file_info, pgchecksum, by = c("source_name", "source_version", "id", "filename")) - if(nrow(lacking_pgchecksum)>0){ - stop("pgchecksum data is outdated. Please contact the administrators of PRIO-GRID.") + if (nrow(lacking_pgchecksum) > 0) { + warning( + nrow(lacking_pgchecksum), " file(s) have no reference checksum in pgchecksum and will be skipped.\n", + " These are likely sources added after the last tested build.\n", + " Sources without checksums: ", + paste(unique(lacking_pgchecksum$source_name), collapse = ", "), "\n", + " Run pg_update_checksums() to update the reference checksums.", + call. = FALSE) } - local_checksum <- file_info |> dplyr::mutate( - local_md5 = tools::md5sum(file.path(destfolder, filename)) - ) |> dplyr::select(source_name, source_version, id, filename, local_md5) + # Only check files present locally + file_info$local_path <- file.path(destfolder, file_info$filename) + present_files <- file_info[file.exists(file_info$local_path), ] - df <- dplyr::left_join(local_checksum, pgchecksum, by = c("source_name", "source_version", "id", "filename")) |> - dplyr::mutate(files_are_equal = local_md5 == md5) + if (nrow(present_files) == 0) { + message("No local raw files found in: ", destfolder, + "\nRun download_pg_rawdata() first.") + return(invisible(NULL)) + } - if(all(df$files_are_equal)){ - print("All files in your local storage are similar to a tested set.") - } else{ - print("Some files in your local storage are different to a tested set. Please see the returned data.frame for details.") + checkable <- dplyr::inner_join( + present_files, pgchecksum, by = c("source_name", "source_version", "id", "filename") + ) + + if (nrow(checkable) == 0) { + message("None of the locally present files have reference checksums in pgchecksum.") + return(invisible(NULL)) } - return(df) + + checkable$local_md5 <- tools::md5sum(checkable$local_path) + df <- dplyr::mutate(checkable, files_are_equal = local_md5 == md5) |> + dplyr::select(source_name, source_version, id, filename, local_md5, md5, files_are_equal) + + n_ok <- sum(df$files_are_equal) + n_bad <- sum(!df$files_are_equal) + + if (verbose) { + if (n_bad == 0) { + message("All ", n_ok, " checked file(s) match the tested reference checksums.") + } else { + message( + n_ok, " file(s) match. ", n_bad, " file(s) differ from tested checksums:\n ", + paste(df$filename[!df$files_are_equal], collapse = "\n "), "\n", + "These may be updated versions or corrupted downloads.\n", + "Re-download with: download_pg_rawdata(..., overwrite = TRUE)") + } + } + return(invisible(df)) } #' Get file-path on local system to a data source in PRIO-GRID @@ -125,30 +156,68 @@ check_pgsourcefiles <- function(){ #' #' @examples #' get_pgfile(source_name = "ETH ICR cShapes", source_version = "2.0", id = "ec3eea2e-6bec-40d5-a09c-e9c6ff2f8b6b") -get_pgfile <- function(source_name, source_version, id){ +get_pgfile <- function(source_name, source_version, id, + verify_checksums = pg_current_config()$verify_checksums) { file_info <- pg_rawfiles() |> dplyr::filter(source_name == !!rlang::enquo(source_name), source_version == !!rlang::enquo(source_version), id == !!rlang::enquo(id)) destfolder <- pg_rawfolder() - if(length(file_info$filename) == 0){ - return(message("No files in metadata with that name and version.")) + + if (length(file_info$filename) == 0) { + stop(sprintf( + "No files found in metadata for source_name='%s', source_version='%s', id='%s'.\n", + source_name, source_version, id), + " Use pgsearch() or pg_rawfiles() to check available sources.", + call. = FALSE) } - if(!dir.exists(destfolder)){ + if (!dir.exists(destfolder)) { stop(paste(destfolder, "does not exist. Please use pg_set_rawfolder().")) } full_file_path <- file.path(destfolder, file_info$filename) file_found <- file.exists(full_file_path) - if(!all(file_found) & pg_current_config()$automatic_download){ - missing_files <- full_file_path[!file.exists(full_file_path)] + if (!all(file_found) & pg_current_config()$automatic_download) { download_pg_rawdata(file_info = file_info) } file_found <- file.exists(full_file_path) - if(!all(file_found)){ - stop(paste("Some files were not found in", destfolder, ":\n", file_info$filename[!file_found], "\n See ?download_pg_rawfiles")) + if (!all(file_found)) { + missing_names <- file_info$filename[!file_found] + if (pg_current_config()$automatic_download) { + stop(sprintf( + "%d file(s) for '%s' v%s not found after download attempt:\n %s\n", + sum(!file_found), source_name, source_version, + paste(missing_names, collapse = "\n ")), + " The download may have failed or been interrupted.\n", + " Try download_pg_rawdata() manually, or check pg_data_availability().", + call. = FALSE) + } else { + stop(sprintf( + "%d file(s) for '%s' v%s are missing from '%s':\n %s\n", + sum(!file_found), source_name, source_version, destfolder, + paste(missing_names, collapse = "\n ")), + " automatic_download is FALSE, so no download was attempted.\n", + " Run download_pg_rawdata() or set automatic_download=TRUE in pg_config().", + call. = FALSE) + } + } + + if (isTRUE(verify_checksums)) { + checkable <- dplyr::inner_join(file_info, pgchecksum, + by = c("source_name", "source_version", "id", "filename")) + if (nrow(checkable) > 0) { + checkable$local_md5 <- tools::md5sum(file.path(destfolder, checkable$filename)) + mismatches <- checkable[checkable$local_md5 != checkable$md5, ] + if (nrow(mismatches) > 0) { + warning(nrow(mismatches), " file(s) for '", source_name, + "' do not match tested checksums:\n ", + paste(mismatches$filename, collapse = "\n "), "\n", + " Run check_pgsourcefiles() for details, or re-download with overwrite=TRUE.", + call. = FALSE) + } + } } return(full_file_path) @@ -261,16 +330,90 @@ download_pg_rawdata <- function(file_info = NULL, overwrite = FALSE, batch_size unfinished_files <- batch_download(file_info, batch_size) - if(nrow(unfinished_files) == 0){ - return() + for(i in seq_len(max_retry)){ + if(nrow(unfinished_files) == 0) break + warning("Download was interrupted before finished. Resuming.", call. = FALSE) + unfinished_files <- batch_download(unfinished_files, batch_size) } - for(i in 1:max_retry){ - warning("Download was interrupted before finished. Resuming.") - unfinished_files <- batch_download(unfinished_files, batch_size) + if (nrow(unfinished_files) > 0) { + message(nrow(unfinished_files), " file(s) could not be downloaded after ", max_retry, + " retries: ", paste(unfinished_files$filename, collapse = ", ")) + } - if(nrow(unfinished_files) == 0){ - return() + # Verify MD5 of newly downloaded files against pgchecksum where available + successful_files <- file_info[!file_info$url %in% unfinished_files$url, ] + checkable <- dplyr::inner_join(successful_files, pgchecksum, + by = c("source_name", "source_version", "id", "filename")) + if (nrow(checkable) > 0) { + message("Verifying MD5 checksums for ", nrow(checkable), " downloaded file(s)...") + checkable$local_md5 <- tools::md5sum(file.path(destfolder, checkable$filename)) + mismatches <- checkable[checkable$local_md5 != checkable$md5, ] + if (nrow(mismatches) > 0) { + warning( + nrow(mismatches), " downloaded file(s) do not match tested checksums:\n", + paste(sprintf(" %s\n expected %s\n got %s", + mismatches$filename, mismatches$md5, mismatches$local_md5), + collapse = "\n"), "\n", + " These may be updated versions. Run check_pgsourcefiles() for a full report.", + call. = FALSE) + } else { + message("All ", nrow(checkable), " downloaded file(s) match tested checksums.") } } + + invisible(NULL) +} + +#' Regenerate pgchecksum from locally verified files +#' +#' Developer-facing function that recomputes MD5 checksums for all raw source +#' files currently present in the raw data folder and saves them to +#' `data/pgchecksum.rda`. Replaces the manual `data_raw/pgchecksum.R` script. +#' +#' Only run this when you have a fully verified, clean set of downloaded files. +#' The resulting `pgchecksum` object is bundled with the package and used by +#' [check_pgsourcefiles()] and the optional checksum verification in [get_pgfile()]. +#' +#' @param only_present Logical. If TRUE (default), only compute checksums for +#' files currently present in the raw folder. If FALSE, stops if any metadata +#' file is missing locally. +#' +#' @return A data.frame of checksums (invisibly). Also saves to `data/pgchecksum.rda`. +#' @export +#' +#' @examples +#' \dontrun{ +#' pg_update_checksums() +#' } +pg_update_checksums <- function(only_present = TRUE) { + rlang::check_installed("usethis", reason = "to save pgchecksum.rda") + destfolder <- pg_rawfolder() + file_info <- pg_rawfiles() + file_info$exists <- file.exists(file.path(destfolder, file_info$filename)) + + if (!only_present && !all(file_info$exists)) { + missing <- file_info$filename[!file_info$exists] + stop( + sum(!file_info$exists), " file(s) not found locally (only_present=FALSE requires all files):\n", + paste(missing, collapse = "\n"), + call. = FALSE) + } + + if (only_present) { + file_info <- file_info[file_info$exists, ] + } + + if (nrow(file_info) == 0) { + stop("No local raw files found. Download files first with download_pg_rawdata().", call. = FALSE) + } + + message("Computing MD5 for ", nrow(file_info), " file(s)...") + pgchecksum <- file_info |> + dplyr::mutate(md5 = tools::md5sum(file.path(destfolder, filename))) |> + dplyr::select(source_name, source_version, id, filename, md5) + + usethis::use_data(pgchecksum, overwrite = TRUE) + message("pgchecksum saved to data/pgchecksum.rda (", nrow(pgchecksum), " entries).") + invisible(pgchecksum) } From 7cb8466ac40cc6b3f077c25b952994919f6e1956 Mon Sep 17 00:00:00 2001 From: Jonas Vestby Date: Tue, 19 May 2026 08:33:05 +0200 Subject: [PATCH 2/7] made tests faster to run + small bug fixes --- NAMESPACE | 1 + R/download_data.R | 2 +- man/get_pgfile.Rd | 7 +++++- man/load_pgvariable.Rd | 3 ++- man/pg_config.Rd | 3 ++- man/pg_update_checksums.Rd | 31 +++++++++++++++++++++++++ man/read_pg_static.Rd | 3 ++- man/read_pg_timevarying.Rd | 3 ++- tests/testthat/helper-priogrid.R | 5 +++- tests/testthat/test-build_priogrid.R | 4 ++-- tests/testthat/test-data_cshapes.R | 8 +++---- tests/testthat/test-data_naturalearth.R | 4 ++-- 12 files changed, 58 insertions(+), 16 deletions(-) create mode 100644 man/pg_update_checksums.Rd diff --git a/NAMESPACE b/NAMESPACE index 4e0f548..842ef32 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -71,6 +71,7 @@ export(pg_release_config) export(pg_reset_config) export(pg_set_config) export(pg_set_rawfolder) +export(pg_update_checksums) export(pgcitations) export(pgout_path) export(pgsearch) diff --git a/R/download_data.R b/R/download_data.R index 862f7d9..a698f8e 100644 --- a/R/download_data.R +++ b/R/download_data.R @@ -320,7 +320,7 @@ download_pg_rawdata <- function(file_info = NULL, overwrite = FALSE, batch_size download_report <- dplyr::bind_rows(download_reports) |> dplyr::filter(!(success %in% c(TRUE))) # NA or FALSE if(nrow(download_report) == 0){ - return(dplyr::tibble()) + return(file_info[0, ]) } unfinished_files <- file_info[file_info$url %in% download_report$url,] diff --git a/man/get_pgfile.Rd b/man/get_pgfile.Rd index 1c23c43..fbf94cd 100644 --- a/man/get_pgfile.Rd +++ b/man/get_pgfile.Rd @@ -4,7 +4,12 @@ \alias{get_pgfile} \title{Get file-path on local system to a data source in PRIO-GRID} \usage{ -get_pgfile(source_name, source_version, id) +get_pgfile( + source_name, + source_version, + id, + verify_checksums = pg_current_config()$verify_checksums +) } \arguments{ \item{src_name}{character, the source name} diff --git a/man/load_pgvariable.Rd b/man/load_pgvariable.Rd index 59debda..26f9396 100644 --- a/man/load_pgvariable.Rd +++ b/man/load_pgvariable.Rd @@ -10,7 +10,8 @@ load_pgvariable( version = NULL, type = "05deg_yearly", spatial_hash = NULL, - temporal_hash = NULL + temporal_hash = NULL, + verify_checksums = FALSE ) } \arguments{ diff --git a/man/pg_config.Rd b/man/pg_config.Rd index af0eb62..f2ff213 100644 --- a/man/pg_config.Rd +++ b/man/pg_config.Rd @@ -13,7 +13,8 @@ pg_config( start_date = as.Date("1850-12-31"), end_date = Sys.Date(), verbose = TRUE, - automatic_download = TRUE + automatic_download = TRUE, + verify_checksums = FALSE ) } \arguments{ diff --git a/man/pg_update_checksums.Rd b/man/pg_update_checksums.Rd new file mode 100644 index 0000000..4075144 --- /dev/null +++ b/man/pg_update_checksums.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/download_data.R +\name{pg_update_checksums} +\alias{pg_update_checksums} +\title{Regenerate pgchecksum from locally verified files} +\usage{ +pg_update_checksums(only_present = TRUE) +} +\arguments{ +\item{only_present}{Logical. If TRUE (default), only compute checksums for +files currently present in the raw folder. If FALSE, stops if any metadata +file is missing locally.} +} +\value{ +A data.frame of checksums (invisibly). Also saves to \code{data/pgchecksum.rda}. +} +\description{ +Developer-facing function that recomputes MD5 checksums for all raw source +files currently present in the raw data folder and saves them to +\code{data/pgchecksum.rda}. Replaces the manual \code{data_raw/pgchecksum.R} script. +} +\details{ +Only run this when you have a fully verified, clean set of downloaded files. +The resulting \code{pgchecksum} object is bundled with the package and used by +\code{\link[=check_pgsourcefiles]{check_pgsourcefiles()}} and the optional checksum verification in \code{\link[=get_pgfile]{get_pgfile()}}. +} +\examples{ +\dontrun{ +pg_update_checksums() +} +} diff --git a/man/read_pg_static.Rd b/man/read_pg_static.Rd index 5cf40d7..9228fae 100644 --- a/man/read_pg_static.Rd +++ b/man/read_pg_static.Rd @@ -12,7 +12,8 @@ read_pg_static( temporal_hash = NULL, as_raster = FALSE, test = FALSE, - overwrite = FALSE + overwrite = FALSE, + verify_checksums = FALSE ) } \arguments{ diff --git a/man/read_pg_timevarying.Rd b/man/read_pg_timevarying.Rd index edd5e13..a4f61ff 100644 --- a/man/read_pg_timevarying.Rd +++ b/man/read_pg_timevarying.Rd @@ -12,7 +12,8 @@ read_pg_timevarying( temporal_hash = NULL, as_raster = FALSE, test = FALSE, - overwrite = FALSE + overwrite = FALSE, + verify_checksums = FALSE ) } \arguments{ diff --git a/tests/testthat/helper-priogrid.R b/tests/testthat/helper-priogrid.R index 4dac0f0..0b62738 100644 --- a/tests/testthat/helper-priogrid.R +++ b/tests/testthat/helper-priogrid.R @@ -1,6 +1,9 @@ # Skip test if raw data folder is unset skip_if_no_rawdata <- function() { - tryCatch(pg_rawfolder(), error = function(e) testthat::skip("Raw data folder not set")) + tryCatch({ + folder <- pg_rawfolder() + if (!dir.exists(folder)) testthat::skip("Raw data folder does not exist") + }, error = function(e) testthat::skip("Raw data folder not set")) } # Tiny config for fast tests that need no downloaded data diff --git a/tests/testthat/test-build_priogrid.R b/tests/testthat/test-build_priogrid.R index 2c90022..1bfc4da 100644 --- a/tests/testthat/test-build_priogrid.R +++ b/tests/testthat/test-build_priogrid.R @@ -89,7 +89,7 @@ test_that("calc_pg writes _config.R on first creation", { withr::with_envvar(list(), { pg_set_rawfolder(tmp_raw) - calc_pg(pgvariables$name[1], config = cfg) + calc_pg("naturalearth_cover_share", config = cfg) s_hash <- priogrid:::get_spatial_hash(cfg) t_hash <- priogrid:::get_temporal_hash(cfg) @@ -115,7 +115,7 @@ test_that("pg_list_custom returns configs and prints summary", { on.exit(unlink(tmp_raw, recursive = TRUE), add = TRUE) pg_set_rawfolder(tmp_raw) - calc_pg(pgvariables$name[1], config = cfg) + calc_pg("naturalearth_cover_share", config = cfg) output <- capture.output(customs <- pg_list_custom()) expect_length(customs, 1L) diff --git a/tests/testthat/test-data_cshapes.R b/tests/testthat/test-data_cshapes.R index a21f4a7..b387e69 100644 --- a/tests/testthat/test-data_cshapes.R +++ b/tests/testthat/test-data_cshapes.R @@ -2,9 +2,7 @@ test_that("gen_cshapes_cover_share returns a multi-layer SpatRaster", { skip_if_no_rawdata() skip_if_not_installed("terra") skip_if_not_installed("sf") - pg_set_config(start_date = as.Date("2010-12-31"), end_date = as.Date("2011-12-31")) - on.exit(pg_reset_config(), add = TRUE) - res <- gen_cshapes_cover_share() + res <- gen_cshapes_cover_share(config = test_config()) testthat::expect_s4_class(res, "SpatRaster") testthat::expect_gt(terra::nlyr(res), 0) }) @@ -13,7 +11,7 @@ test_that("cshapes_cover_share returns a raster for a specific date", { skip_if_no_rawdata() skip_if_not_installed("terra") skip_if_not_installed("sf") - res <- cshapes_cover_share(as.Date("2010-01-01")) + res <- cshapes_cover_share(as.Date("2010-01-01"), config = test_config()) testthat::expect_s4_class(res, "SpatRaster") }) @@ -21,7 +19,7 @@ test_that("cshapes_cover returns a raster with boolean values", { skip_if_no_rawdata() skip_if_not_installed("terra") skip_if_not_installed("sf") - res <- cshapes_cover(as.Date("2010-01-01")) + res <- cshapes_cover(as.Date("2010-01-01"), config = test_config()) testthat::expect_s4_class(res, "SpatRaster") testthat::expect_true(terra::is.bool(res)) }) diff --git a/tests/testthat/test-data_naturalearth.R b/tests/testthat/test-data_naturalearth.R index 798831b..aae256b 100644 --- a/tests/testthat/test-data_naturalearth.R +++ b/tests/testthat/test-data_naturalearth.R @@ -2,7 +2,7 @@ test_that("gen_naturalearth_cover_share returns a raster", { skip_if_no_rawdata() skip_if_not_installed("terra") skip_if_not_installed("sf") - res <- gen_naturalearth_cover_share() + res <- gen_naturalearth_cover_share(config = test_config()) testthat::expect_s4_class(res, "SpatRaster") }) @@ -10,7 +10,7 @@ test_that("gen_naturalearth_cover returns a raster with boolean values", { skip_if_no_rawdata() skip_if_not_installed("terra") skip_if_not_installed("sf") - res <- gen_naturalearth_cover() + res <- gen_naturalearth_cover(config = test_config()) testthat::expect_s4_class(res, "SpatRaster") testthat::expect_true(terra::is.bool(res)) }) From e69688b6d1cbbda9616d710efeebf34286c7648e Mon Sep 17 00:00:00 2001 From: Jonas Vestby Date: Tue, 19 May 2026 08:33:26 +0200 Subject: [PATCH 3/7] doc update --- man/check_pgsourcefiles.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/check_pgsourcefiles.Rd b/man/check_pgsourcefiles.Rd index 4ad8cbd..1db099e 100644 --- a/man/check_pgsourcefiles.Rd +++ b/man/check_pgsourcefiles.Rd @@ -4,7 +4,7 @@ \alias{check_pgsourcefiles} \title{Test if MD5 checksums of local files are the same as a tested set of files} \usage{ -check_pgsourcefiles() +check_pgsourcefiles(verbose = TRUE) } \value{ data.frame From 7a1a78f38e37c8bd8f6574adcd2e406083de8564 Mon Sep 17 00:00:00 2001 From: Jonas Vestby Date: Tue, 19 May 2026 10:01:22 +0200 Subject: [PATCH 4/7] checked and fixed documentation for missing/wrong parameters --- R/build_priogrid.R | 10 ++++++++++ R/data_SHDI.R | 11 +++++++++++ R/data_crupet.R | 4 ++++ R/data_crupre.R | 4 ++++ R/data_crutmp.R | 3 +++ R/data_cshapes.R | 12 ++++++++++++ R/data_geoEPR.R | 1 + R/data_geopko.R | 4 ++++ R/data_ghs_wup.R | 3 +++ R/data_ghsl.R | 4 ++++ R/data_hilda.R | 9 +++++++++ R/data_linight.R | 3 +++ R/data_naturalearth.R | 8 ++++++-- R/data_ruggedterrain.R | 3 +++ R/data_speibase.R | 6 +++++- R/data_traveltime.R | 5 +++++ R/data_ucdp.R | 3 +++ R/download_data.R | 15 +++++++++++---- man/calc_pg.Rd | 2 ++ man/calc_traveltime.Rd | 2 ++ man/check_pgsourcefiles.Rd | 3 +++ man/download_pg_rawdata.Rd | 4 +++- man/download_priogrid.Rd | 3 +++ man/gen_bdist2.Rd | 8 ++++++++ man/gen_bdist3.Rd | 8 ++++++++ man/gen_cru_pet.Rd | 3 +++ man/gen_cru_pre.Rd | 3 +++ man/gen_cru_tmp.Rd | 3 +++ man/gen_esch.Rd | 3 +++ man/gen_geoepr_reg_excluded.Rd | 2 ++ man/gen_geopko_operations_count.Rd | 3 +++ man/gen_geopko_troops_count.Rd | 3 +++ man/gen_ghs_wup_degurba_urban.Rd | 3 +++ man/gen_ghsl_population_grid.Rd | 3 +++ man/gen_gnic.Rd | 3 +++ man/gen_hilda_cropland.Rd | 3 +++ man/gen_hilda_forest.Rd | 3 +++ man/gen_hilda_grassland.Rd | 3 +++ man/gen_hilda_ocean.Rd | 3 +++ man/gen_hilda_pasture.Rd | 3 +++ man/gen_hilda_sparse.Rd | 3 +++ man/gen_hilda_urban.Rd | 3 +++ man/gen_hilda_water.Rd | 3 +++ man/gen_lifexp.Rd | 3 +++ man/gen_linight_mean.Rd | 3 +++ man/gen_msch.Rd | 3 +++ man/gen_naturalearth_cover.Rd | 2 ++ man/gen_naturalearth_cover_share.Rd | 3 +++ man/gen_ne_disputed_area_share.Rd | 3 +++ man/gen_ruggedterrain_elevation_mean.Rd | 3 +++ man/gen_shdi.Rd | 3 +++ man/gen_speibase6_mean.Rd | 3 +++ man/gen_traveltime_mean.Rd | 3 +++ man/gen_traveltime_min.Rd | 3 +++ man/gen_ucdp_ged.Rd | 3 +++ man/get_pgfile.Rd | 9 +++++++-- man/hilda_landcover.Rd | 2 ++ man/load_pgvariable.Rd | 3 +++ man/ne_disputed_area_share.Rd | 3 +-- man/pg_rawfiles.Rd | 2 ++ man/pgout_path.Rd | 2 ++ man/read_cru_pet.Rd | 3 +++ man/read_cru_pre.Rd | 3 +++ man/read_cru_tmp.Rd | 2 ++ man/read_ghsl_population_grid.Rd | 3 +++ man/read_linight.Rd | 2 ++ man/read_pg_static.Rd | 3 +++ man/read_pg_timevarying.Rd | 3 +++ man/read_speibase.Rd | 2 ++ man/ruggedterrain_variable.Rd | 2 ++ man/shdi.Rd | 2 ++ man/spei.nc.Rd | 2 ++ man/speibaseN.Rd | 2 ++ man/ucdp_ged.Rd | 2 ++ man/urban_extent.Rd | 2 ++ 75 files changed, 268 insertions(+), 12 deletions(-) diff --git a/R/build_priogrid.R b/R/build_priogrid.R index c9e6cfa..cdf3f27 100644 --- a/R/build_priogrid.R +++ b/R/build_priogrid.R @@ -52,6 +52,7 @@ get_temporal_hash <- function(config = pg_current_config()) { #' @param type Character string specifying release type (e.g., "05deg_yearly"). Use for official releases. #' @param spatial_hash Character string with 6-character spatial hash. If NULL, computed from current config. #' @param temporal_hash Character string with 6-character temporal hash. If NULL, computed from current config. +#' @param config A `pg_config` object. Defaults to [pg_current_config()]. #' #' @return Character string with file path #' @export @@ -101,6 +102,7 @@ pgout_path <- function(version = NULL, #' If NULL (default), calculates all available variables. #' @param overwrite Logical. If FALSE (default), skips variables that already #' exist in the output folder. If TRUE, recalculates all specified variables. +#' @param config A `pg_config` object. Defaults to [pg_current_config()]. #' #' @return NULL (invisibly). Called for side effects (saving files). #' @export @@ -295,6 +297,8 @@ save_pgvariable <- function(rast, varname, save_to = pgout_path()) { #' temporal_hash. Loads from the specified custom folder directly. #' @param temporal_hash Character string with 6-character temporal hash. Requires #' spatial_hash. +#' @param verify_checksums Logical. If TRUE, verifies the file's MD5 checksum +#' against stored values. Default FALSE. #' #' @return Terra SpatRaster object #' @export @@ -509,6 +513,8 @@ resolve_pg_mode <- function(config = NULL, #' @param test Logical. If TRUE, prints coverage summary for each variable. #' @param overwrite Logical. If FALSE (default) and cached file exists, returns #' cached data. If TRUE, rebuilds from individual variables. +#' @param verify_checksums Logical. If TRUE, verifies checksums of cached files +#' against stored MD5 values. Default FALSE. #' #' @return data.table with pgid as rows and variables as columns, or list of #' terra SpatRasters if as_raster=TRUE @@ -649,6 +655,8 @@ read_pg_static <- function(config = NULL, #' @param test Logical. If TRUE, returns coverage summary data.frame. #' @param overwrite Logical. If FALSE (default) and cached file exists, returns #' cached data. If TRUE, rebuilds from individual variables. +#' @param verify_checksums Logical. If TRUE, verifies checksums of cached files +#' against stored MD5 values. Default FALSE. #' #' @return data.table with pgid + measurement_date as rows and variables as columns, #' or list of terra SpatRasters if as_raster=TRUE, or coverage test data.frame if test=TRUE @@ -928,6 +936,8 @@ pg_list_custom <- function() { #' @param version Character string with release version #' @param type Character string with release type (default: "05deg_yearly") #' @param overwrite Logical. If TRUE, re-downloads even if file exists. +#' @param list_releases Logical. If TRUE, prints and returns a data.frame of +#' available releases instead of downloading. Default FALSE. #' #' @return NULL (invisibly). Called for side effects (downloading data). #' @export diff --git a/R/data_SHDI.R b/R/data_SHDI.R index aa1bd25..7893ebe 100644 --- a/R/data_SHDI.R +++ b/R/data_SHDI.R @@ -266,6 +266,7 @@ read_shdi <- function(shdi_csv = read_shdi_csv(), #' \item \code{"gnic"} – Gross national income per capita #' } #' Default is \code{"shdi"}. +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' #' @return A \code{SpatRaster} object (from the \pkg{terra} package) aligned to the #' PRIO-GRID, containing the selected SHDI variable aggregated to grid cells using @@ -350,6 +351,8 @@ shdi <- function(variable = "shdi", config = pg_current_config()) { #' Convenience wrapper around \code{\link{shdi}} that generates a PRIO-GRID–aligned #' raster of the Subnational Human Development Index (SHDI). #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object containing PRIO-GRID SHDI values. #' #' @examples @@ -373,6 +376,8 @@ gen_shdi <- function(config = pg_current_config()) { #' Convenience wrapper around \code{\link{shdi}} that generates a PRIO-GRID–aligned #' raster of mean years of schooling. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object containing PRIO-GRID mean years of schooling. #' #' @examples @@ -396,6 +401,8 @@ gen_msch <- function(config = pg_current_config()) { #' Convenience wrapper around \code{\link{shdi}} that generates a PRIO-GRID–aligned #' raster of expected years of schooling. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object containing PRIO-GRID expected years of schooling. #' #' @examples @@ -419,6 +426,8 @@ gen_esch <- function(config = pg_current_config()) { #' Convenience wrapper around \code{\link{shdi}} that generates a PRIO-GRID–aligned #' raster of life expectancy at birth. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object containing PRIO-GRID life expectancy values. #' #' @examples @@ -442,6 +451,8 @@ gen_lifexp <- function(config = pg_current_config()) { #' Convenience wrapper around \code{\link{shdi}} that generates a PRIO-GRID–aligned #' raster of gross national income per capita. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object containing PRIO-GRID GNI per capita values. #' #' @examples diff --git a/R/data_crupet.R b/R/data_crupet.R index a495eb5..8c0fc8b 100644 --- a/R/data_crupet.R +++ b/R/data_crupet.R @@ -25,6 +25,8 @@ #' pet_data <- read_cru_pet() #' } #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @seealso #' \code{\link{get_pgfile}} for file retrieval functionality, #' \code{\link{pg_date_intervals}} for PRIO-GRID temporal boundaries @@ -70,6 +72,8 @@ read_cru_pet <- function(config = pg_current_config()) { #' r <- gen_cru_pet() #' } #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @seealso #' \code{\link{read_cru_pet}}, \code{\link{pg_date_intervals}}, #' \code{\link{robust_transformation}}, \code{\link{get_pgfile}} diff --git a/R/data_crupre.R b/R/data_crupre.R index 14ff5ee..fe7757f 100644 --- a/R/data_crupre.R +++ b/R/data_crupre.R @@ -25,6 +25,8 @@ #' pre_data <- read_cru_pre() #' } #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @seealso #' \code{\link{get_pgfile}} for file retrieval functionality, #' \code{\link{pg_date_intervals}} for PRIO-GRID temporal boundaries @@ -76,6 +78,8 @@ read_cru_pre <- function(config = pg_current_config()) { #' r <- gen_cru_pre() #' } #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @seealso #' \code{\link{read_cru_pre}}, \code{\link{pg_date_intervals}}, #' \code{\link{robust_transformation}}, \code{\link{get_pgfile}} diff --git a/R/data_crutmp.R b/R/data_crutmp.R index 8801a08..5454673 100644 --- a/R/data_crutmp.R +++ b/R/data_crutmp.R @@ -10,6 +10,7 @@ #' dataset. Available options include "tmp" (temperature), "stn" (station count), #' "mae" (mean absolute error), and "maea". #' Default is "tmp". +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' #' @return A \code{SpatRaster} object (from the \pkg{terra} package) with the #' following characteristics: @@ -82,6 +83,8 @@ read_cru_tmp <- function(variable = "tmp", config = pg_current_config()) { #' This takes the CRU TS dataset and aggregates it in time and space to #' PRIO-GRID specifications. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object (from the \pkg{terra} package) with spatio-temporal #' resolution as defined in PRIO-GRID. #' diff --git a/R/data_cshapes.R b/R/data_cshapes.R index e5a7c2e..481bbef 100644 --- a/R/data_cshapes.R +++ b/R/data_cshapes.R @@ -635,6 +635,12 @@ bdist2 <- function(measurement_date, cshp = read_cshapes(), past_result = NULL, #' #' @param cshp An \code{sf} object containing CShapes 2.0 boundary data with #' temporal information. Defaults to \code{\link{read_cshapes}()} if not provided. +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' @param geodesic Logical or NULL. If TRUE, computes distances in WGS84 using +#' spherical (S2) geometry and reprojects the result to the config CRS. If +#' FALSE, uses Euclidean distances in the config CRS. Default NULL +#' auto-detects: geodesic for projected CRS (e.g. UTM), native for geographic +#' CRS (e.g. WGS84, which terra already handles geodesically). #' #' @return A \code{SpatRaster} object #' @@ -796,6 +802,12 @@ bdist3 <- function(measurement_date, cshp = read_cshapes(), past_result = NULL, #' #' @param cshp An \code{sf} object containing CShapes 2.0 boundary data with #' temporal information. Defaults to \code{\link{read_cshapes}()} if not provided. +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' @param geodesic Logical or NULL. If TRUE, computes distances in WGS84 using +#' spherical (S2) geometry and reprojects the result to the config CRS. If +#' FALSE, uses Euclidean distances in the config CRS. Default NULL +#' auto-detects: geodesic for projected CRS (e.g. UTM), native for geographic +#' CRS (e.g. WGS84, which terra already handles geodesically). #' #' @return A \code{SpatRaster} object #' diff --git a/R/data_geoEPR.R b/R/data_geoEPR.R index 485a601..a0f21d0 100644 --- a/R/data_geoEPR.R +++ b/R/data_geoEPR.R @@ -192,6 +192,7 @@ read_epr <- function() { #' \item "STATE COLLAPSE": Groups during state collapse periods #' } #' Default is \code{c("DISCRIMINATED", "POWERLESS", "SELF-EXCLUSION")}. +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' #' @examples #' \dontrun{ diff --git a/R/data_geopko.R b/R/data_geopko.R index 1287604..ff92f94 100644 --- a/R/data_geopko.R +++ b/R/data_geopko.R @@ -96,6 +96,8 @@ read_geopko <- function(){ #' aggregates Geo-PKO deployment locations to grid cells, providing a measure #' of peacekeeping intensity and geographic distribution over time. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object #' @export #' @@ -174,6 +176,8 @@ gen_geopko_operations_count <- function(config = pg_current_config()) { #' The function aggregates Geo-PKO troop deployment data to grid cells, #' providing a measure of peacekeeping force strength and geographic distribution over time. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object #' #' @note diff --git a/R/data_ghs_wup.R b/R/data_ghs_wup.R index de127d9..7b1222c 100644 --- a/R/data_ghs_wup.R +++ b/R/data_ghs_wup.R @@ -219,6 +219,8 @@ ghs_wup_degurba <- function(urban_definition, config = pg_current_config()){ #' #' A slight nearest neighbor resampling was applied to get the exact PRIO-GRID extent. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object with values ranging from 0 to 1 #' #' @note @@ -293,6 +295,7 @@ gen_ghs_wup_degurba_urban <- function(config = pg_current_config()){ #' @param max_extent Numeric. Maximum search radius in meters around the input #' coordinates. Default is 1000000 (1000 km). This limits the area searched #' for connected urban patches and improves computational efficiency. +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' #' @details #' The function performs the following workflow: diff --git a/R/data_ghsl.R b/R/data_ghsl.R index dacd94a..0734bf2 100644 --- a/R/data_ghsl.R +++ b/R/data_ghsl.R @@ -16,6 +16,8 @@ #' \item Provides population data at 5-year intervals (typically 1975-2030) #' } #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object #' #' @note @@ -105,6 +107,8 @@ read_ghsl_population_grid <- function(config = pg_current_config()){ #' #' A slight nearest neighbor resampling was applied to get the exact PRIO-GRID extent. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object #' #' @note diff --git a/R/data_hilda.R b/R/data_hilda.R index 9309a33..41ae5a2 100644 --- a/R/data_hilda.R +++ b/R/data_hilda.R @@ -117,6 +117,7 @@ read_hilda <- function(config = pg_current_config()) { #' \item 77: Water #' \item 99: No data #' } +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' #' @return A \code{SpatRaster} object (terra package) with the same structure as #' PRIO-GRID, where each cell contains the proportion (0-1) of that cell covered @@ -167,6 +168,7 @@ hilda_landcover <- function(landcovertype, config = pg_current_config()){ #' A convenience wrapper for \code{\link{hilda_landcover}} that extracts #' ocean coverage proportions (class code 00) for PRIO-GRID cells. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' @return A \code{SpatRaster} with ocean coverage proportions (0-1) for each #' PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. #' @seealso \code{\link{hilda_landcover}} for full documentation and parameters @@ -180,6 +182,7 @@ gen_hilda_ocean <- function(config = pg_current_config()){ #' A convenience wrapper for \code{\link{hilda_landcover}} that extracts #' urban coverage proportions (class code 11) for PRIO-GRID cells. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' @return A \code{SpatRaster} with urban coverage proportions (0-1) for each #' PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. #' @seealso \code{\link{hilda_landcover}} for full documentation and parameters @@ -193,6 +196,7 @@ gen_hilda_urban <- function(config = pg_current_config()){ #' A convenience wrapper for \code{\link{hilda_landcover}} that extracts #' cropland coverage proportions (class code 22) for PRIO-GRID cells. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' @return A \code{SpatRaster} with cropland coverage proportions (0-1) for each #' PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. #' @seealso \code{\link{hilda_landcover}} for full documentation and parameters @@ -206,6 +210,7 @@ gen_hilda_cropland <- function(config = pg_current_config()){ #' A convenience wrapper for \code{\link{hilda_landcover}} that extracts #' pasture/rangeland coverage proportions (class code 33) for PRIO-GRID cells. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' @return A \code{SpatRaster} with pasture/rangeland coverage proportions (0-1) #' for each PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. #' @seealso \code{\link{hilda_landcover}} for full documentation and parameters @@ -219,6 +224,7 @@ gen_hilda_pasture <- function(config = pg_current_config()){ #' A convenience wrapper for \code{\link{hilda_landcover}} that extracts #' forest coverage proportions (class code 44) for PRIO-GRID cells. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' @return A \code{SpatRaster} with forest coverage proportions (0-1) for each #' PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. #' @seealso \code{\link{hilda_landcover}} for full documentation and parameters @@ -232,6 +238,7 @@ gen_hilda_forest <- function(config = pg_current_config()){ #' A convenience wrapper for \code{\link{hilda_landcover}} that extracts #' unmanaged grass/shrubland coverage proportions (class code 55) for PRIO-GRID cells. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' @return A \code{SpatRaster} with unmanaged grass/shrubland coverage proportions #' (0-1) for each PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. #' @seealso \code{\link{hilda_landcover}} for full documentation and parameters @@ -245,6 +252,7 @@ gen_hilda_grassland <- function(config = pg_current_config()){ #' A convenience wrapper for \code{\link{hilda_landcover}} that extracts #' sparse/no vegetation coverage proportions (class code 66) for PRIO-GRID cells. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' @return A \code{SpatRaster} with sparse/no vegetation coverage proportions #' (0-1) for each PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. #' @seealso \code{\link{hilda_landcover}} for full documentation and parameters @@ -258,6 +266,7 @@ gen_hilda_sparse <- function(config = pg_current_config()){ #' A convenience wrapper for \code{\link{hilda_landcover}} that extracts #' water coverage proportions (class code 77) for PRIO-GRID cells. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' @return A \code{SpatRaster} with water coverage proportions (0-1) for each #' PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. #' @seealso \code{\link{hilda_landcover}} for full documentation and parameters diff --git a/R/data_linight.R b/R/data_linight.R index 500ca16..b51fd25 100644 --- a/R/data_linight.R +++ b/R/data_linight.R @@ -23,6 +23,7 @@ #' #' @param overwrite_files Logical. If \code{TRUE}, previously fixed rasters are #' recalculated and overwritten. Defaults to \code{FALSE}. +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' #' @return A \code{SpatRaster} object #' @@ -145,6 +146,8 @@ read_linight <- function(overwrite_files = FALSE, config = pg_current_config()){ #' in \code{\link{read_linight}}) #' } #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object #' #' @note diff --git a/R/data_naturalearth.R b/R/data_naturalearth.R index e268d5a..dbcd018 100644 --- a/R/data_naturalearth.R +++ b/R/data_naturalearth.R @@ -107,6 +107,8 @@ read_ne_disputed_areas <- function() { #' layer aligned to PRIO-GRID resolution with values in the range \code{[0, 1]} #' indicating land coverage share. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A single-layer \code{SpatRaster} object #' #' @note @@ -179,6 +181,7 @@ gen_naturalearth_cover_share <- function(config = pg_current_config()){ #' @param min_cover Numeric, default \code{0}. Minimum fraction of a grid cell #' that must be covered by land for the cell to be classified as land. #' Should be between \code{0} and \code{1}. +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' #' @return A single-layer \code{SpatRaster} object #' @@ -215,8 +218,7 @@ gen_naturalearth_cover <- function(min_cover = 0, config = pg_current_config()){ #' @param type Character string specifying the type of disputed area to include. #' Valid options are: "all", "breakaway", "disputed", "geo subunit", "geo unit", #' "indeterminate", "lease", or "overlay". -#' @param disputed_areas Optional \code{sf} object of disputed areas. Defaults -#' to the result of \code{\link{read_ne_disputed_areas}}(). +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' #' @return A single-layer \code{SpatRaster} object #' @@ -287,6 +289,8 @@ ne_disputed_area_share <- function(type, config = pg_current_config()) { #' \code{\link{ne_disputed_area_share}}, automatically using \code{type = "all"} #' to combine all disputed area types into a single raster layer. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A single-layer \code{SpatRaster} object #' #' @examples diff --git a/R/data_ruggedterrain.R b/R/data_ruggedterrain.R index 2f04718..eba23c8 100644 --- a/R/data_ruggedterrain.R +++ b/R/data_ruggedterrain.R @@ -63,6 +63,7 @@ read_ruggedterrain <- function() { #' #' @param variable Character string indicating elevation function. #' Must be one of: "elevation_min", "elevation_max", "elevation_mean" +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' #' @return A \code{SpatRaster} object #' @export @@ -135,6 +136,8 @@ ruggedterrain_variable <- function(variable, config = pg_current_config()) { #' A convenience wrapper function that calculates mean elevation values for each #' PRIO-GRID cell using \code{\link{ruggedterrain_variable}}. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object #' @export #' diff --git a/R/data_speibase.R b/R/data_speibase.R index b7730c2..d82090f 100644 --- a/R/data_speibase.R +++ b/R/data_speibase.R @@ -9,6 +9,7 @@ #' @param inMask Character vector. Path to a netCDF mask file. #' @param block Integer. Number of latitude blocks to be processed at the #' same time. Must be an integer dividend of 360. +#' @param tlapse Numeric. Temperature lapse rate. Default NA. #' #' @return Computes the SPEI time series and stores it in outFile following #' the same data structure of inPre. @@ -192,6 +193,7 @@ spei.nc <- function(sca, inPre, outFile, inEtp=NA, title=NA, comment=NA, #' @param interval Integer. The month interval to calculate SPEI over. E.g., if the interval is #' 6, then monthly precipitation and potential evapotranspiration are aggregated over the last 6 months, #' then the SPEI (anomaly) is calculated. This is done for each month. +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' #' @seealso #' \code{\link{get_pgfile}} for file retrieval functionality, @@ -268,7 +270,7 @@ read_speibase <- function(interval = 6, config = pg_current_config()) { #' then the SPEI (anomaly) is calculated. This is done for each month. #' @param time_agg_fun Character. Either "mean" or "max". Original data is monthly, so if PRIO-GRID is lower #' resolution, then we need to aggregate over time. Currently, mean and max functions are implemented. -#' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' #' @return A \code{SpatRaster} object (from the \pkg{terra} package) with spatio-temporal #' resolution as defined in PRIO-GRID. @@ -331,6 +333,8 @@ speibaseN <- function(interval, time_agg_fun, config = pg_current_config()){ #' or other intervals), while also performing spatial aggregation to the PRIO-GRID resolution. #' #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A \code{SpatRaster} object (from the \pkg{terra} package) with spatio-temporal #' resolution as defined in PRIO-GRID. #' diff --git a/R/data_traveltime.R b/R/data_traveltime.R index 3002e3f..b18f47b 100644 --- a/R/data_traveltime.R +++ b/R/data_traveltime.R @@ -72,6 +72,7 @@ read_traveltime <- function() { #' #' @param aggregation_function Function or character string specifying the #' aggregation method (see details above) +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' #' @return A \code{SpatRaster} object #' @@ -106,6 +107,8 @@ calc_traveltime <- function(aggregation_function, config = pg_current_config()) #' using \code{aggregation_function = "min"}. It reads the global travel time #' raster and summarizes each PRIO-GRID cell to the minimum travel time value. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A single-layer \code{SpatRaster} object #' #' @examples @@ -140,6 +143,8 @@ gen_traveltime_min <- function(config = pg_current_config()){ #' using \code{aggregation_function = "mean"}. It reads the global travel time #' raster and summarizes each PRIO-GRID cell to the mean travel time value. #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @return A single-layer \code{SpatRaster} object #' #' @examples diff --git a/R/data_ucdp.R b/R/data_ucdp.R index 4f66b94..50ad894 100644 --- a/R/data_ucdp.R +++ b/R/data_ucdp.R @@ -180,6 +180,7 @@ rasterize_ged_crossection <- function(ged, pg_interval, fatality_variable, confi #' \item "high": High estimate of fatalities #' \item "event_count": Count of events rather than fatalities #' } +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. #' #' @return A \code{SpatRaster} object with multiple layers, one for each time #' interval in \code{\link{pg_date_intervals}}. Layer names correspond to @@ -364,6 +365,8 @@ ucdp_ged <- function(ged = read_ucdp_ged(), violence_types = c(1,2,3), fatality_ #' \item NA values: Grid cells with no recorded events or outside state system #' } #' +#' @param config A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}. +#' #' @note #' \itemize{ #' \item Processing time depends on the size of the UCDP GED dataset diff --git a/R/download_data.R b/R/download_data.R index a698f8e..9a49d6c 100644 --- a/R/download_data.R +++ b/R/download_data.R @@ -38,6 +38,7 @@ pgsearch <- function(search_string, bib_element = NULL){ #' Extract url- and file-info from PRIO-GRID metadata #' #' @param use_mirror Boolean. Whether or not to use PRIO-GRID mirror. +#' @param only_file_extensions Logical. If TRUE, returns file extensions only. Used for testing. Default FALSE. #' #' @return data.frame #' @export @@ -83,6 +84,8 @@ pg_rawfiles <- function(use_mirror = TRUE, only_file_extensions = FALSE){ #' local files. This is to verify that you are using the same files #' as we used to build PRIO-GRID. #' +#' @param verbose Logical. If TRUE (default), prints a summary message. +#' #' @return data.frame #' @export #' @@ -148,8 +151,11 @@ check_pgsourcefiles <- function(verbose = TRUE){ #' #' To look up src_name and version in PRIO-GRID, see [pg_rawfiles()]. #' -#' @param src_name character, the source name -#' @param version character, the version number +#' @param source_name Character. The source name. +#' @param source_version Character. The version number. +#' @param id Character. The source id (UUID). +#' @param verify_checksums Logical. If TRUE, verifies file checksums against +#' stored MD5 values. Defaults to value from [pg_current_config()]. #' #' @return file path, string #' @export @@ -259,10 +265,11 @@ pg_data_availability <- function() { #' #' Before running this, you need to set the folder using pg_set_rawfolder("path/to/folder") #' -#' @param overwrite Whether or not to download and overwrite files already in local folder. #' @param file_info A data.frame with the same structure as the result from [pg_rawfiles()]. If file_info is null (default), #' then file_info will be all data returned from [pg_rawfiles()]. -#' @param resume If true, will also download files that did not finish download last time the function was run. +#' @param overwrite Whether or not to download and overwrite files already in local folder. +#' @param batch_size Integer. Number of files per download batch. Default 20. +#' @param max_retry Integer. Maximum number of retry attempts for failed downloads. Default 10. #' #' @return data.frame Download summary #' @export diff --git a/man/calc_pg.Rd b/man/calc_pg.Rd index 4b76a8f..77112e8 100644 --- a/man/calc_pg.Rd +++ b/man/calc_pg.Rd @@ -12,6 +12,8 @@ If NULL (default), calculates all available variables.} \item{overwrite}{Logical. If FALSE (default), skips variables that already exist in the output folder. If TRUE, recalculates all specified variables.} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link[=pg_current_config]{pg_current_config()}}.} } \value{ NULL (invisibly). Called for side effects (saving files). diff --git a/man/calc_traveltime.Rd b/man/calc_traveltime.Rd index a500e65..60be2dd 100644 --- a/man/calc_traveltime.Rd +++ b/man/calc_traveltime.Rd @@ -9,6 +9,8 @@ calc_traveltime(aggregation_function, config = pg_current_config()) \arguments{ \item{aggregation_function}{Function or character string specifying the aggregation method (see details above)} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} } \value{ A \code{SpatRaster} object diff --git a/man/check_pgsourcefiles.Rd b/man/check_pgsourcefiles.Rd index 1db099e..eaa51e7 100644 --- a/man/check_pgsourcefiles.Rd +++ b/man/check_pgsourcefiles.Rd @@ -6,6 +6,9 @@ \usage{ check_pgsourcefiles(verbose = TRUE) } +\arguments{ +\item{verbose}{Logical. If TRUE (default), prints a summary message.} +} \value{ data.frame } diff --git a/man/download_pg_rawdata.Rd b/man/download_pg_rawdata.Rd index 1df631d..fa0837d 100644 --- a/man/download_pg_rawdata.Rd +++ b/man/download_pg_rawdata.Rd @@ -17,7 +17,9 @@ then file_info will be all data returned from \code{\link[=pg_rawfiles]{pg_rawfi \item{overwrite}{Whether or not to download and overwrite files already in local folder.} -\item{resume}{If true, will also download files that did not finish download last time the function was run.} +\item{batch_size}{Integer. Number of files per download batch. Default 20.} + +\item{max_retry}{Integer. Maximum number of retry attempts for failed downloads. Default 10.} } \value{ data.frame Download summary diff --git a/man/download_priogrid.Rd b/man/download_priogrid.Rd index a2c402f..52a6b02 100644 --- a/man/download_priogrid.Rd +++ b/man/download_priogrid.Rd @@ -17,6 +17,9 @@ download_priogrid( \item{type}{Character string with release type (default: "05deg_yearly")} \item{overwrite}{Logical. If TRUE, re-downloads even if file exists.} + +\item{list_releases}{Logical. If TRUE, prints and returns a data.frame of +available releases instead of downloading. Default FALSE.} } \value{ NULL (invisibly). Called for side effects (downloading data). diff --git a/man/gen_bdist2.Rd b/man/gen_bdist2.Rd index 0d9806f..3076dd1 100644 --- a/man/gen_bdist2.Rd +++ b/man/gen_bdist2.Rd @@ -9,6 +9,14 @@ gen_bdist2(cshp = read_cshapes(), config = pg_current_config()) \arguments{ \item{cshp}{An \code{sf} object containing CShapes 2.0 boundary data with temporal information. Defaults to \code{\link{read_cshapes}()} if not provided.} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} + +\item{geodesic}{Logical or NULL. If TRUE, computes distances in WGS84 using +spherical (S2) geometry and reprojects the result to the config CRS. If +FALSE, uses Euclidean distances in the config CRS. Default NULL +auto-detects: geodesic for projected CRS (e.g. UTM), native for geographic +CRS (e.g. WGS84, which terra already handles geodesically).} } \value{ A \code{SpatRaster} object diff --git a/man/gen_bdist3.Rd b/man/gen_bdist3.Rd index 30d9309..7312958 100644 --- a/man/gen_bdist3.Rd +++ b/man/gen_bdist3.Rd @@ -13,6 +13,14 @@ gen_bdist3( \arguments{ \item{cshp}{An \code{sf} object containing CShapes 2.0 boundary data with temporal information. Defaults to \code{\link{read_cshapes}()} if not provided.} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} + +\item{geodesic}{Logical or NULL. If TRUE, computes distances in WGS84 using +spherical (S2) geometry and reprojects the result to the config CRS. If +FALSE, uses Euclidean distances in the config CRS. Default NULL +auto-detects: geodesic for projected CRS (e.g. UTM), native for geographic +CRS (e.g. WGS84, which terra already handles geodesically).} } \value{ A \code{SpatRaster} object diff --git a/man/gen_cru_pet.Rd b/man/gen_cru_pet.Rd index 0f357b7..5648bf7 100644 --- a/man/gen_cru_pet.Rd +++ b/man/gen_cru_pet.Rd @@ -6,6 +6,9 @@ \usage{ gen_cru_pet(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object with PRIO-GRID spatio-temporal resolution. } diff --git a/man/gen_cru_pre.Rd b/man/gen_cru_pre.Rd index ddc481c..3b23282 100644 --- a/man/gen_cru_pre.Rd +++ b/man/gen_cru_pre.Rd @@ -6,6 +6,9 @@ \usage{ gen_cru_pre(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object with PRIO-GRID spatio-temporal resolution. } diff --git a/man/gen_cru_tmp.Rd b/man/gen_cru_tmp.Rd index 3a2d7b7..4eebaa3 100644 --- a/man/gen_cru_tmp.Rd +++ b/man/gen_cru_tmp.Rd @@ -6,6 +6,9 @@ \usage{ gen_cru_tmp(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object (from the \pkg{terra} package) with spatio-temporal resolution as defined in PRIO-GRID. diff --git a/man/gen_esch.Rd b/man/gen_esch.Rd index 4ff1c4c..6f7bca9 100644 --- a/man/gen_esch.Rd +++ b/man/gen_esch.Rd @@ -6,6 +6,9 @@ \usage{ gen_esch(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object containing PRIO-GRID expected years of schooling. } diff --git a/man/gen_geoepr_reg_excluded.Rd b/man/gen_geoepr_reg_excluded.Rd index 5772942..c3bcb99 100644 --- a/man/gen_geoepr_reg_excluded.Rd +++ b/man/gen_geoepr_reg_excluded.Rd @@ -24,6 +24,8 @@ gen_geoepr_reg_excluded( \item "STATE COLLAPSE": Groups during state collapse periods } Default is \code{c("DISCRIMINATED", "POWERLESS", "SELF-EXCLUSION")}.} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} } \value{ A \code{SpatRaster} object diff --git a/man/gen_geopko_operations_count.Rd b/man/gen_geopko_operations_count.Rd index 853037a..06c2e85 100644 --- a/man/gen_geopko_operations_count.Rd +++ b/man/gen_geopko_operations_count.Rd @@ -6,6 +6,9 @@ \usage{ gen_geopko_operations_count(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object } diff --git a/man/gen_geopko_troops_count.Rd b/man/gen_geopko_troops_count.Rd index 7d8188f..e23ce36 100644 --- a/man/gen_geopko_troops_count.Rd +++ b/man/gen_geopko_troops_count.Rd @@ -6,6 +6,9 @@ \usage{ gen_geopko_troops_count(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object } diff --git a/man/gen_ghs_wup_degurba_urban.Rd b/man/gen_ghs_wup_degurba_urban.Rd index d201a73..3b24a04 100644 --- a/man/gen_ghs_wup_degurba_urban.Rd +++ b/man/gen_ghs_wup_degurba_urban.Rd @@ -6,6 +6,9 @@ \usage{ gen_ghs_wup_degurba_urban(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object with values ranging from 0 to 1 } diff --git a/man/gen_ghsl_population_grid.Rd b/man/gen_ghsl_population_grid.Rd index a4d3175..da5c20d 100644 --- a/man/gen_ghsl_population_grid.Rd +++ b/man/gen_ghsl_population_grid.Rd @@ -6,6 +6,9 @@ \usage{ gen_ghsl_population_grid(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object } diff --git a/man/gen_gnic.Rd b/man/gen_gnic.Rd index ae87bef..2057543 100644 --- a/man/gen_gnic.Rd +++ b/man/gen_gnic.Rd @@ -6,6 +6,9 @@ \usage{ gen_gnic(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object containing PRIO-GRID GNI per capita values. } diff --git a/man/gen_hilda_cropland.Rd b/man/gen_hilda_cropland.Rd index 0876573..eee1db9 100644 --- a/man/gen_hilda_cropland.Rd +++ b/man/gen_hilda_cropland.Rd @@ -6,6 +6,9 @@ \usage{ gen_hilda_cropland(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} with cropland coverage proportions (0-1) for each PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. diff --git a/man/gen_hilda_forest.Rd b/man/gen_hilda_forest.Rd index 98fc045..9c7501b 100644 --- a/man/gen_hilda_forest.Rd +++ b/man/gen_hilda_forest.Rd @@ -6,6 +6,9 @@ \usage{ gen_hilda_forest(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} with forest coverage proportions (0-1) for each PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. diff --git a/man/gen_hilda_grassland.Rd b/man/gen_hilda_grassland.Rd index 131c8a3..6f6727b 100644 --- a/man/gen_hilda_grassland.Rd +++ b/man/gen_hilda_grassland.Rd @@ -6,6 +6,9 @@ \usage{ gen_hilda_grassland(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} with unmanaged grass/shrubland coverage proportions (0-1) for each PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. diff --git a/man/gen_hilda_ocean.Rd b/man/gen_hilda_ocean.Rd index 1d7b646..6fa7b71 100644 --- a/man/gen_hilda_ocean.Rd +++ b/man/gen_hilda_ocean.Rd @@ -6,6 +6,9 @@ \usage{ gen_hilda_ocean(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} with ocean coverage proportions (0-1) for each PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. diff --git a/man/gen_hilda_pasture.Rd b/man/gen_hilda_pasture.Rd index 46e01c1..e0c59d3 100644 --- a/man/gen_hilda_pasture.Rd +++ b/man/gen_hilda_pasture.Rd @@ -6,6 +6,9 @@ \usage{ gen_hilda_pasture(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} with pasture/rangeland coverage proportions (0-1) for each PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. diff --git a/man/gen_hilda_sparse.Rd b/man/gen_hilda_sparse.Rd index 5b2f917..7a9abbd 100644 --- a/man/gen_hilda_sparse.Rd +++ b/man/gen_hilda_sparse.Rd @@ -6,6 +6,9 @@ \usage{ gen_hilda_sparse(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} with sparse/no vegetation coverage proportions (0-1) for each PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. diff --git a/man/gen_hilda_urban.Rd b/man/gen_hilda_urban.Rd index 8b50ee9..e2ad3fa 100644 --- a/man/gen_hilda_urban.Rd +++ b/man/gen_hilda_urban.Rd @@ -6,6 +6,9 @@ \usage{ gen_hilda_urban(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} with urban coverage proportions (0-1) for each PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. diff --git a/man/gen_hilda_water.Rd b/man/gen_hilda_water.Rd index c9e9b5f..92d4499 100644 --- a/man/gen_hilda_water.Rd +++ b/man/gen_hilda_water.Rd @@ -6,6 +6,9 @@ \usage{ gen_hilda_water(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} with water coverage proportions (0-1) for each PRIO-GRID cell. See \code{\link{hilda_landcover}} for details. diff --git a/man/gen_lifexp.Rd b/man/gen_lifexp.Rd index 8efa86a..7761747 100644 --- a/man/gen_lifexp.Rd +++ b/man/gen_lifexp.Rd @@ -6,6 +6,9 @@ \usage{ gen_lifexp(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object containing PRIO-GRID life expectancy values. } diff --git a/man/gen_linight_mean.Rd b/man/gen_linight_mean.Rd index 8f0d03b..eb53137 100644 --- a/man/gen_linight_mean.Rd +++ b/man/gen_linight_mean.Rd @@ -6,6 +6,9 @@ \usage{ gen_linight_mean(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object } diff --git a/man/gen_msch.Rd b/man/gen_msch.Rd index 74d32f9..7bc58c5 100644 --- a/man/gen_msch.Rd +++ b/man/gen_msch.Rd @@ -6,6 +6,9 @@ \usage{ gen_msch(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object containing PRIO-GRID mean years of schooling. } diff --git a/man/gen_naturalearth_cover.Rd b/man/gen_naturalearth_cover.Rd index 07669ee..697993e 100644 --- a/man/gen_naturalearth_cover.Rd +++ b/man/gen_naturalearth_cover.Rd @@ -10,6 +10,8 @@ gen_naturalearth_cover(min_cover = 0, config = pg_current_config()) \item{min_cover}{Numeric, default \code{0}. Minimum fraction of a grid cell that must be covered by land for the cell to be classified as land. Should be between \code{0} and \code{1}.} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} } \value{ A single-layer \code{SpatRaster} object diff --git a/man/gen_naturalearth_cover_share.Rd b/man/gen_naturalearth_cover_share.Rd index da1f39a..bd520e1 100644 --- a/man/gen_naturalearth_cover_share.Rd +++ b/man/gen_naturalearth_cover_share.Rd @@ -6,6 +6,9 @@ \usage{ gen_naturalearth_cover_share(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A single-layer \code{SpatRaster} object } diff --git a/man/gen_ne_disputed_area_share.Rd b/man/gen_ne_disputed_area_share.Rd index fd25f23..4aed38b 100644 --- a/man/gen_ne_disputed_area_share.Rd +++ b/man/gen_ne_disputed_area_share.Rd @@ -6,6 +6,9 @@ \usage{ gen_ne_disputed_area_share(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A single-layer \code{SpatRaster} object } diff --git a/man/gen_ruggedterrain_elevation_mean.Rd b/man/gen_ruggedterrain_elevation_mean.Rd index 55eb517..2849479 100644 --- a/man/gen_ruggedterrain_elevation_mean.Rd +++ b/man/gen_ruggedterrain_elevation_mean.Rd @@ -6,6 +6,9 @@ \usage{ gen_ruggedterrain_elevation_mean(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object } diff --git a/man/gen_shdi.Rd b/man/gen_shdi.Rd index 3b6be2f..abc1d97 100644 --- a/man/gen_shdi.Rd +++ b/man/gen_shdi.Rd @@ -6,6 +6,9 @@ \usage{ gen_shdi(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object containing PRIO-GRID SHDI values. } diff --git a/man/gen_speibase6_mean.Rd b/man/gen_speibase6_mean.Rd index 7ad4e36..3458a3d 100644 --- a/man/gen_speibase6_mean.Rd +++ b/man/gen_speibase6_mean.Rd @@ -6,6 +6,9 @@ \usage{ gen_speibase6_mean(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object (from the \pkg{terra} package) with spatio-temporal resolution as defined in PRIO-GRID. diff --git a/man/gen_traveltime_mean.Rd b/man/gen_traveltime_mean.Rd index 5d7e64c..e4fe95b 100644 --- a/man/gen_traveltime_mean.Rd +++ b/man/gen_traveltime_mean.Rd @@ -6,6 +6,9 @@ \usage{ gen_traveltime_mean(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A single-layer \code{SpatRaster} object } diff --git a/man/gen_traveltime_min.Rd b/man/gen_traveltime_min.Rd index 49bf328..8f504ed 100644 --- a/man/gen_traveltime_min.Rd +++ b/man/gen_traveltime_min.Rd @@ -6,6 +6,9 @@ \usage{ gen_traveltime_min(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A single-layer \code{SpatRaster} object } diff --git a/man/gen_ucdp_ged.Rd b/man/gen_ucdp_ged.Rd index 8cd0d60..2e86fed 100644 --- a/man/gen_ucdp_ged.Rd +++ b/man/gen_ucdp_ged.Rd @@ -6,6 +6,9 @@ \usage{ gen_ucdp_ged(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object with multiple layers, one for each time interval defined in \code{\link{pg_date_intervals}}. Each layer contains: diff --git a/man/get_pgfile.Rd b/man/get_pgfile.Rd index fbf94cd..6629b71 100644 --- a/man/get_pgfile.Rd +++ b/man/get_pgfile.Rd @@ -12,9 +12,14 @@ get_pgfile( ) } \arguments{ -\item{src_name}{character, the source name} +\item{source_name}{Character. The source name.} -\item{version}{character, the version number} +\item{source_version}{Character. The version number.} + +\item{id}{Character. The source id (UUID).} + +\item{verify_checksums}{Logical. If TRUE, verifies file checksums against +stored MD5 values. Defaults to value from \code{\link[=pg_current_config]{pg_current_config()}}.} } \value{ file path, string diff --git a/man/hilda_landcover.Rd b/man/hilda_landcover.Rd index 04d9eda..fd81cd5 100644 --- a/man/hilda_landcover.Rd +++ b/man/hilda_landcover.Rd @@ -23,6 +23,8 @@ HILDA+ land cover class codes (for stable categories): \item 77: Water \item 99: No data }} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} } \value{ A \code{SpatRaster} object (terra package) with the same structure as diff --git a/man/load_pgvariable.Rd b/man/load_pgvariable.Rd index 26f9396..855b9e0 100644 --- a/man/load_pgvariable.Rd +++ b/man/load_pgvariable.Rd @@ -31,6 +31,9 @@ temporal_hash. Loads from the specified custom folder directly.} \item{temporal_hash}{Character string with 6-character temporal hash. Requires spatial_hash.} + +\item{verify_checksums}{Logical. If TRUE, verifies the file's MD5 checksum +against stored values. Default FALSE.} } \value{ Terra SpatRaster object diff --git a/man/ne_disputed_area_share.Rd b/man/ne_disputed_area_share.Rd index 48870a1..7eb8abb 100644 --- a/man/ne_disputed_area_share.Rd +++ b/man/ne_disputed_area_share.Rd @@ -11,8 +11,7 @@ ne_disputed_area_share(type, config = pg_current_config()) Valid options are: "all", "breakaway", "disputed", "geo subunit", "geo unit", "indeterminate", "lease", or "overlay".} -\item{disputed_areas}{Optional \code{sf} object of disputed areas. Defaults -to the result of \code{\link{read_ne_disputed_areas}}().} +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} } \value{ A single-layer \code{SpatRaster} object diff --git a/man/pg_rawfiles.Rd b/man/pg_rawfiles.Rd index 409393e..302cd99 100644 --- a/man/pg_rawfiles.Rd +++ b/man/pg_rawfiles.Rd @@ -8,6 +8,8 @@ pg_rawfiles(use_mirror = TRUE, only_file_extensions = FALSE) } \arguments{ \item{use_mirror}{Boolean. Whether or not to use PRIO-GRID mirror.} + +\item{only_file_extensions}{Logical. If TRUE, returns file extensions only. Used for testing. Default FALSE.} } \value{ data.frame diff --git a/man/pgout_path.Rd b/man/pgout_path.Rd index 5fc5db4..95359bf 100644 --- a/man/pgout_path.Rd +++ b/man/pgout_path.Rd @@ -20,6 +20,8 @@ pgout_path( \item{spatial_hash}{Character string with 6-character spatial hash. If NULL, computed from current config.} \item{temporal_hash}{Character string with 6-character temporal hash. If NULL, computed from current config.} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link[=pg_current_config]{pg_current_config()}}.} } \value{ Character string with file path diff --git a/man/read_cru_pet.Rd b/man/read_cru_pet.Rd index 89e6ebe..1b61fd5 100644 --- a/man/read_cru_pet.Rd +++ b/man/read_cru_pet.Rd @@ -6,6 +6,9 @@ \usage{ read_cru_pet(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object (from the \pkg{terra} package) with the following characteristics: diff --git a/man/read_cru_pre.Rd b/man/read_cru_pre.Rd index 2e02505..ec6871c 100644 --- a/man/read_cru_pre.Rd +++ b/man/read_cru_pre.Rd @@ -6,6 +6,9 @@ \usage{ read_cru_pre(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object (from the \pkg{terra} package) with the following characteristics: diff --git a/man/read_cru_tmp.Rd b/man/read_cru_tmp.Rd index ef62ff2..ed0f030 100644 --- a/man/read_cru_tmp.Rd +++ b/man/read_cru_tmp.Rd @@ -12,6 +12,8 @@ from the raster stack. Must match the prefix of variable names in the CRU dataset. Available options include "tmp" (temperature), "stn" (station count), "mae" (mean absolute error), and "maea". Default is "tmp".} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} } \value{ A \code{SpatRaster} object (from the \pkg{terra} package) with the diff --git a/man/read_ghsl_population_grid.Rd b/man/read_ghsl_population_grid.Rd index 8c0ca61..062fd37 100644 --- a/man/read_ghsl_population_grid.Rd +++ b/man/read_ghsl_population_grid.Rd @@ -6,6 +6,9 @@ \usage{ read_ghsl_population_grid(config = pg_current_config()) } +\arguments{ +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} +} \value{ A \code{SpatRaster} object } diff --git a/man/read_linight.Rd b/man/read_linight.Rd index b91ad9d..22823a8 100644 --- a/man/read_linight.Rd +++ b/man/read_linight.Rd @@ -9,6 +9,8 @@ read_linight(overwrite_files = FALSE, config = pg_current_config()) \arguments{ \item{overwrite_files}{Logical. If \code{TRUE}, previously fixed rasters are recalculated and overwritten. Defaults to \code{FALSE}.} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} } \value{ A \code{SpatRaster} object diff --git a/man/read_pg_static.Rd b/man/read_pg_static.Rd index 9228fae..7dc31d8 100644 --- a/man/read_pg_static.Rd +++ b/man/read_pg_static.Rd @@ -35,6 +35,9 @@ official release.} \item{overwrite}{Logical. If FALSE (default) and cached file exists, returns cached data. If TRUE, rebuilds from individual variables.} + +\item{verify_checksums}{Logical. If TRUE, verifies checksums of cached files +against stored MD5 values. Default FALSE.} } \value{ data.table with pgid as rows and variables as columns, or list of diff --git a/man/read_pg_timevarying.Rd b/man/read_pg_timevarying.Rd index a4f61ff..c6f8851 100644 --- a/man/read_pg_timevarying.Rd +++ b/man/read_pg_timevarying.Rd @@ -35,6 +35,9 @@ official release.} \item{overwrite}{Logical. If FALSE (default) and cached file exists, returns cached data. If TRUE, rebuilds from individual variables.} + +\item{verify_checksums}{Logical. If TRUE, verifies checksums of cached files +against stored MD5 values. Default FALSE.} } \value{ data.table with pgid + measurement_date as rows and variables as columns, diff --git a/man/read_speibase.Rd b/man/read_speibase.Rd index 2bcfd3f..edbbb44 100644 --- a/man/read_speibase.Rd +++ b/man/read_speibase.Rd @@ -10,6 +10,8 @@ read_speibase(interval = 6, config = pg_current_config()) \item{interval}{Integer. The month interval to calculate SPEI over. E.g., if the interval is 6, then monthly precipitation and potential evapotranspiration are aggregated over the last 6 months, then the SPEI (anomaly) is calculated. This is done for each month.} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} } \description{ While this data can be downloaded from the Global SPEI database, it is only open diff --git a/man/ruggedterrain_variable.Rd b/man/ruggedterrain_variable.Rd index 02ba903..3da4204 100644 --- a/man/ruggedterrain_variable.Rd +++ b/man/ruggedterrain_variable.Rd @@ -9,6 +9,8 @@ ruggedterrain_variable(variable, config = pg_current_config()) \arguments{ \item{variable}{Character string indicating elevation function. Must be one of: "elevation_min", "elevation_max", "elevation_mean"} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} } \value{ A \code{SpatRaster} object diff --git a/man/shdi.Rd b/man/shdi.Rd index 7ae3e9a..3aa9e73 100644 --- a/man/shdi.Rd +++ b/man/shdi.Rd @@ -17,6 +17,8 @@ generate. Supported values include: \item \code{"gnic"} – Gross national income per capita } Default is \code{"shdi"}.} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} } \value{ A \code{SpatRaster} object (from the \pkg{terra} package) aligned to the diff --git a/man/spei.nc.Rd b/man/spei.nc.Rd index e5e36e2..2b36b75 100644 --- a/man/spei.nc.Rd +++ b/man/spei.nc.Rd @@ -36,6 +36,8 @@ spei.nc( \item{block}{Integer. Number of latitude blocks to be processed at the same time. Must be an integer dividend of 360.} + +\item{tlapse}{Numeric. Temperature lapse rate. Default NA.} } \value{ Computes the SPEI time series and stores it in outFile following diff --git a/man/speibaseN.Rd b/man/speibaseN.Rd index 790ba3f..aa926d1 100644 --- a/man/speibaseN.Rd +++ b/man/speibaseN.Rd @@ -13,6 +13,8 @@ then the SPEI (anomaly) is calculated. This is done for each month.} \item{time_agg_fun}{Character. Either "mean" or "max". Original data is monthly, so if PRIO-GRID is lower resolution, then we need to aggregate over time. Currently, mean and max functions are implemented.} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} } \value{ A \code{SpatRaster} object (from the \pkg{terra} package) with spatio-temporal diff --git a/man/ucdp_ged.Rd b/man/ucdp_ged.Rd index b54bcd9..0ae2fbc 100644 --- a/man/ucdp_ged.Rd +++ b/man/ucdp_ged.Rd @@ -32,6 +32,8 @@ to use. Options are: \item "high": High estimate of fatalities \item "event_count": Count of events rather than fatalities }} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} } \value{ A \code{SpatRaster} object with multiple layers, one for each time diff --git a/man/urban_extent.Rd b/man/urban_extent.Rd index 650f707..b4a4b64 100644 --- a/man/urban_extent.Rd +++ b/man/urban_extent.Rd @@ -30,6 +30,8 @@ Valid codes are: 10, 11, 12, 13, 21, 22, 23, 30. See Details for code meanings.} \item{max_extent}{Numeric. Maximum search radius in meters around the input coordinates. Default is 1000000 (1000 km). This limits the area searched for connected urban patches and improves computational efficiency.} + +\item{config}{A \code{pg_config} object. Defaults to \code{\link{pg_current_config}()}.} } \value{ An \code{sf} polygon object representing the contiguous urban extent From 64d938b8a9f9afd946f004aa53e75c716219c274 Mon Sep 17 00:00:00 2001 From: Jonas Vestby Date: Tue, 19 May 2026 13:48:45 +0200 Subject: [PATCH 5/7] update checksum behavior --- R/build_priogrid.R | 68 ++++++++++++++++++++++++++++ R/download_data.R | 4 +- data_raw/pgchecksum.R | 9 ---- tests/testthat/test-build_priogrid.R | 44 ++++++++++++++++++ 4 files changed, 114 insertions(+), 11 deletions(-) delete mode 100644 data_raw/pgchecksum.R diff --git a/R/build_priogrid.R b/R/build_priogrid.R index cdf3f27..091632a 100644 --- a/R/build_priogrid.R +++ b/R/build_priogrid.R @@ -277,6 +277,74 @@ save_pgvariable <- function(rast, varname, save_to = pgout_path()) { invisible(NULL) } +# Internal admin helper: bulk-bootstrap _checksums.csv for all .rds/.parquet +# files in a resolved output folder. Useful after files have been placed without +# going through save_pgvariable() / read_pg_static() / read_pg_timevarying(). +# +# @param config,version,type,spatial_hash,temporal_hash Passed to resolve_pg_mode(). +# @param overwrite_existing Logical. If FALSE (default), skips files that already +# have an entry in _checksums.csv. If TRUE, recomputes all entries. +# @return A list with elements `n_added` and `n_updated` (integers), invisibly. +# @keywords internal +.pg_bootstrap_checksums <- function(config = NULL, + version = NULL, + type = "05deg_yearly", + spatial_hash = NULL, + temporal_hash = NULL, + overwrite_existing = FALSE) { + + cfg <- resolve_pg_mode(config, version, type, spatial_hash, temporal_hash) + base_path <- cfg$base_path + + if (!dir.exists(base_path)) { + stop("Output directory does not exist: ", base_path, call. = FALSE) + } + + target_files <- list.files(base_path, pattern = "\\.(rds|parquet)$", full.names = FALSE) + + if (length(target_files) == 0) { + message("No .rds or .parquet files found in: ", base_path) + return(invisible(list(n_added = 0L, n_updated = 0L))) + } + + checksum_file <- file.path(base_path, "_checksums.csv") + existing_labels <- if (file.exists(checksum_file)) { + utils::read.csv(checksum_file, stringsAsFactors = FALSE)$varname + } else { + character(0) + } + + n_added <- 0L + n_updated <- 0L + + for (fname in target_files) { + label <- if (grepl("\\.rds$", fname)) tools::file_path_sans_ext(fname) else fname + already_exists <- label %in% existing_labels + + if (already_exists && !overwrite_existing) next + + .pg_record_checksum(file.path(base_path, fname), label, base_path) + + if (already_exists) { + n_updated <- n_updated + 1L + } else { + n_added <- n_added + 1L + existing_labels <- c(existing_labels, label) + } + } + + message( + "Bootstrap complete for: ", base_path, "\n", + " Added: ", n_added, " new checksum(s)\n", + " Updated: ", n_updated, " existing checksum(s)\n", + " Skipped: ", length(target_files) - n_added - n_updated, + " already-present checksum(s) (use overwrite_existing=TRUE to force)" + ) + + invisible(list(n_added = n_added, n_updated = n_updated)) +} + + #' Load a PRIO-GRID variable #' #' Loads a PRIO-GRID variable from disk and returns it as a terra SpatRaster. diff --git a/R/download_data.R b/R/download_data.R index 9a49d6c..d4542a5 100644 --- a/R/download_data.R +++ b/R/download_data.R @@ -387,11 +387,11 @@ download_pg_rawdata <- function(file_info = NULL, overwrite = FALSE, batch_size #' file is missing locally. #' #' @return A data.frame of checksums (invisibly). Also saves to `data/pgchecksum.rda`. -#' @export +#' @keywords internal #' #' @examples #' \dontrun{ -#' pg_update_checksums() +#' priogrid:::pg_update_checksums() #' } pg_update_checksums <- function(only_present = TRUE) { rlang::check_installed("usethis", reason = "to save pgchecksum.rda") diff --git a/data_raw/pgchecksum.R b/data_raw/pgchecksum.R deleted file mode 100644 index bd79e1f..0000000 --- a/data_raw/pgchecksum.R +++ /dev/null @@ -1,9 +0,0 @@ -# Do not run. (Used to test checksums for a verified set of files.) - -destfolder <- pgoptions$get_rawfolder() -file_info <- pg_rawfiles() -pgchecksum <- file_info |> dplyr::mutate( - md5 = tools::md5sum(file.path(destfolder, filename)) -) |> dplyr::select(source_name, source_version, id, filename, md5) -usethis::use_data(pgchecksum, overwrite = FALSE) - diff --git a/tests/testthat/test-build_priogrid.R b/tests/testthat/test-build_priogrid.R index 1bfc4da..8c1bf80 100644 --- a/tests/testthat/test-build_priogrid.R +++ b/tests/testthat/test-build_priogrid.R @@ -122,3 +122,47 @@ test_that("pg_list_custom returns configs and prints summary", { expect_s3_class(customs[[1]], "pg_config") expect_true(any(grepl("\\[1\\]", output))) }) + +test_that(".pg_bootstrap_checksums adds entries for existing files", { + tmp_raw <- tempfile() + dir.create(tmp_raw) + on.exit(unlink(tmp_raw, recursive = TRUE), add = TRUE) + + pg_set_rawfolder(tmp_raw) + cfg <- pg_config() + s_hash <- priogrid:::get_spatial_hash(cfg) + t_hash <- priogrid:::get_temporal_hash(cfg) + out_path <- pgout_path(spatial_hash = s_hash, temporal_hash = t_hash) + dir.create(out_path, recursive = TRUE) + + saveRDS(list(x = 1), file.path(out_path, "fake_var.rds")) + + result <- priogrid:::.pg_bootstrap_checksums(config = cfg) + + checksum_file <- file.path(out_path, "_checksums.csv") + expect_true(file.exists(checksum_file)) + cs <- utils::read.csv(checksum_file, stringsAsFactors = FALSE) + expect_true("fake_var" %in% cs$varname) + expect_equal(result$n_added, 1L) + expect_equal(result$n_updated, 0L) +}) + +test_that(".pg_bootstrap_checksums skips existing entries by default", { + tmp_raw <- tempfile() + dir.create(tmp_raw) + on.exit(unlink(tmp_raw, recursive = TRUE), add = TRUE) + + pg_set_rawfolder(tmp_raw) + cfg <- pg_config() + s_hash <- priogrid:::get_spatial_hash(cfg) + t_hash <- priogrid:::get_temporal_hash(cfg) + out_path <- pgout_path(spatial_hash = s_hash, temporal_hash = t_hash) + dir.create(out_path, recursive = TRUE) + + saveRDS(list(x = 1), file.path(out_path, "fake_var.rds")) + priogrid:::.pg_bootstrap_checksums(config = cfg) + + result2 <- priogrid:::.pg_bootstrap_checksums(config = cfg) + expect_equal(result2$n_added, 0L) + expect_equal(result2$n_updated, 0L) +}) From 33b329ef12a013957af7822e1afbfd2059556c72 Mon Sep 17 00:00:00 2001 From: Jonas Vestby Date: Fri, 22 May 2026 09:56:40 +0200 Subject: [PATCH 6/7] fixed urls for linight data. updated to v10 --- R/data_linight.R | 38 ++++++------------ data/pgsources.rda | Bin 8026 -> 8105 bytes data/pgvariables.rda | Bin 1387 -> 1394 bytes data_raw/sources.csv | 3 +- data_raw/variables.csv | 2 +- .../24d76a3b-927e-42ad-b8a5-2e7443e6a275.txt | 10 +++++ .../d99fbea7-2a01-4221-b900-29a58d33f591.txt | 33 +++++++++++++++ 7 files changed, 59 insertions(+), 27 deletions(-) create mode 100644 inst/extdata/urls/24d76a3b-927e-42ad-b8a5-2e7443e6a275.txt create mode 100644 inst/extdata/urls/d99fbea7-2a01-4221-b900-29a58d33f591.txt diff --git a/R/data_linight.R b/R/data_linight.R index b51fd25..b67824f 100644 --- a/R/data_linight.R +++ b/R/data_linight.R @@ -1,16 +1,15 @@ #' Reads the Li Nighttime data #' #' Downloads, preprocesses, and harmonizes the Li et al. global nighttime -#' light dataset (v8). This dataset provides global, annual composites +#' light dataset (v10). This dataset provides global, annual composites #' of nighttime light intensity, harmonized across multiple satellite #' sensors to produce a consistent multi-decadal time series. #' #' @details #' The function: #' \itemize{ -#' \item Downloads the zipped Li Nighttime Lights raster files from the -#' PRIO-GRID data repository -#' \item Extracts TIF files, caching results to avoid repeated unzipping +#' \item Downloads individual Li Nighttime Lights raster files from the +#' PRIO-GRID data repository via the Figshare API #' \item Identifies rasters with extent mismatches (common in the dataset) #' \item Resamples problematic rasters to a standardized global template #' (\code{EPSG:4326}, extent -180/180, -90/90) using nearest neighbor @@ -66,24 +65,16 @@ #' \insertRef{liHarmonizedGlobalNighttime2020}{priogrid} read_linight <- function(overwrite_files = FALSE, config = pg_current_config()){ - zip_file <- get_pgfile(source_name="Li Nighttime", - source_version="v8", - id="24d76a3b-927e-42ad-b8a5-2e7443e6a275") + allfiles <- get_pgfile(source_name="Li Nighttime", + source_version="v10", + id="d99fbea7-2a01-4221-b900-29a58d33f591") + data_dir <- dirname(allfiles[1]) - suppressWarnings(unzip(zipfile = zip_file, overwrite = overwrite_files, exdir = dirname(zip_file))) - - allfiles <- list.files(dirname(zip_file),pattern = "^Harmonized", full.names = TRUE) - - # Extents vary depending on the source, and is often marginally larger than the world. - #extents <- lapply(allfiles, function(x) terra::ext(terra::rast(x))) - #allfiles[!sapply(extents, function(x) x == terra::ext(c(-180, 180, -90, 90)))] - - fixed_files <- list.files(dirname(zip_file),pattern = "^fixed", full.names = TRUE) + fixed_files <- list.files(data_dir, pattern = "^fixed", full.names = TRUE) if(overwrite_files){ - # Re-calculate from source file file.remove(fixed_files) - fixed_files <- list.files(dirname(zip_file),pattern = "^fixed", full.names = TRUE) + fixed_files <- list.files(data_dir, pattern = "^fixed", full.names = TRUE) } fixed_files <- fixed_files[file.info(fixed_files)$size > 3e7] # can occur if resampling is interrupted @@ -101,9 +92,6 @@ read_linight <- function(overwrite_files = FALSE, config = pg_current_config()){ crs = "EPSG:4326" ) - #template <- terra::rast(x = files_to_fix[1]) - #template <- terra::extend(template, terra::ext(c(-180, 180, -90, 90))) - n <- length(files_to_fix) pb <- txtProgressBar(min = 0, max = n, style = 3) @@ -111,12 +99,12 @@ read_linight <- function(overwrite_files = FALSE, config = pg_current_config()){ setTxtProgressBar(pb, i) rsub <- terra::rast(x = files_to_fix[i]) fname <- paste0("fixed_", basename(files_to_fix[i])) - res <- terra::resample(rsub, template, method = "near", threads = T, overwrite = TRUE, progress = FALSE, filename = file.path(dirname(zip_file), fname)) + res <- terra::resample(rsub, template, method = "near", threads = T, overwrite = TRUE, progress = FALSE, filename = file.path(data_dir, fname)) } close(pb) } - fixed_files <- list.files(dirname(zip_file),pattern = "^fixed", full.names = TRUE) + fixed_files <- list.files(data_dir, pattern = "^fixed", full.names = TRUE) r <- terra::rast(fixed_files) pgmonth <- pg_dates(config)[1] |> lubridate::month() @@ -130,7 +118,7 @@ read_linight <- function(overwrite_files = FALSE, config = pg_current_config()){ #' Generate Li Nighttime Light #' #' Aggregates the high-resolution Li et al. harmonized global nighttime lights -#' dataset to PRIO-GRID resolution for all available years (1992–2021). +#' dataset to PRIO-GRID resolution for all available years (1992–2024). #' This produces PRIO-GRID cell-level averages of nighttime light intensity, #' harmonized with PRIO-GRID’s spatial and temporal structure. #' @@ -140,7 +128,7 @@ read_linight <- function(overwrite_files = FALSE, config = pg_current_config()){ #' \item Reads annual nighttime lights rasters via \code{\link{read_linight}} #' \item Aggregates 1 km nighttime light intensity values into PRIO-GRID #' cells using mean values -#' \item Retains global temporal coverage (1992–2021) as a multi-layer +#' \item Retains global temporal coverage (1992–2024) as a multi-layer #' \code{SpatRaster} #' \item Aligns precisely to PRIO-GRID spatial extent (resampling handled #' in \code{\link{read_linight}}) diff --git a/data/pgsources.rda b/data/pgsources.rda index b74ab6802989eb92c1f65dfb0071dc6b00f038e2..b18a5480994cb0905eab5325a34a7082888429a0 100644 GIT binary patch literal 8105 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 DG`Y;B literal 8026 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 diff --git a/data/pgvariables.rda b/data/pgvariables.rda index 741e0501cd790d0a997876e80d77378cf59f8ea6..d4d4e6df886ca89fa32cdd75d1a9b268dd37103f 100644 GIT binary patch literal 1394 zcmV-&1&#VbT4*^jL0KkKS*@TqJpcsUf5QL&|HMTPf8Yfe7C^u6-@rfs01yBH&;{Oh zu;Pk}IZ`4GI7%QuA)_jOnrWoTk*T#Y28N9Q9+PAsl8L6!n3_U>&;S4dpa1{?DXMu! zs5CUmrc9a!AO?nw0j7Y^(V@*UG8r&KMiT^SqedWUlOq5D1d#;O6wOT~KPE)f%|Lp9 z41tghs0|X}4+FJ>X{Kd&2?jDyT1nUmFos}WERo{L9?$tfhHWB(43HF|NHYuh?fi0r z^;q^%2+=?%YA1s<9Q|1(r96PvVFD8{z-p!%WCee!Kb$wT{=mwt?DxlED$9K`9t^j^ zT+2!%iTa%Ap9eWr>eGjGhllM>N;W(fao(A{QrDU(RLL7LYZ@NCpH1zeSgR1GHaD6R?krxb#6l^10(gA&`8ozFi-|Xq*)k57AA&4G6qqJ zN6L{#QxS!PS}y*&kxB1;Rm&GNGr8~hWle7t05vHSLZhGtxvl1+85x(1r&N4b1=NIS zhH0x;N7LWID32_Wk;n&)POY`LjwFptZXj0i97W%9(J3(xYLLnY(T3l-*rKh*0%A3t z&IqBdSINauw>_CrZqbVfr6nN}#-bplLfont(5&aMiR_L|l!vv*2&4-lOCm_9s^nqo3c_PLOszGc_V)c{} zIA$U?Oou9Bgd&SeMD|0VG343jI)}sh+uXa zg)XX)`MQ8vLr@`b2!S;+j}YWKQq0)R7dCN}He(dY&NNM|3X=jfz~F8yYS#x&BR3y; zuE^wyKv&HWHmRf$S0S`SXa@{%16tlCoQxR{t^`Q46{Uy)nJ58$YH%uyBSNU!Pj(>a zbZ#Z<@#b}R?D%)pxavC9Y`?6pufdOcx;WkpR_m#-;=VI1V^v$R&vHwr3Tw0m2x{4f zNZAX}#Dk=0m?cym+FZe$rnGm6(69`OHCW8d4Fq56_hB5kn?REm5gaO55fmX|<#H#B zE_nz>?0c;r940JblumY&;-t+0PHG|v^f{xh9Ffes{1N9pYR5_lfRD*<)fL|Zp|2I) z)iUbB9Ucb+OWGry?W|DfoWPvG$r7lrF$wD{f)eR!6%@@(G?$w^%d~!eVfa70{!)qD zkKcgIAvn2KoO+<)rjRZ!aPrq9-i;8}hLuKMbViOwjLVvSijF(FTsY|qcdZR5sWH^`FbW+RZ+Fi_~>)5C*UWK8=gnDo8VB?mM2 z0LYEJuyc`<1~K{)TGiECU=b4m8A;f+Oa%)giBefnNCO4H{H_t|v5hb34E7*~a|V*0 zQj2ZqruI-@=v~|QJ!^KU-fD@MrkJHPa+>6yw1EqGvQ0v(6JXkL%?6A~-ot!T=A?yr z1`~>qco^`t#L*^r(=%*^$98fOjvET6QYQ)_Lwx1j7_uAbIRE1ANT&)C6|@HDpfxpl A`~Uy| literal 1387 zcmV-x1(f zYybdu?x$u!AW9%0DVYhe34qlyJwRvypbZ-$1f@?<84Uv<0000001W^Jnj)t4O`CYpLc7)%7nVq=DyWMVLyU?G4_FpLuuA*M!#fJqQ0jWQuJn2kUKY5*Rf(U57N zG?x%~9ySgWOv=s@4XB{6CtxJP8G(Nckk(NK|MX%B?TdK*_W-GBdm8BAm5DCjx|t!6Q0iV-*63wndSIMPjI;3Xvf>nZ7idAyE-n zMze4FPghCbLgkH34NuR{o-ZW;FjrGT!$b^8a4;f>k$L4?Bha|7W_hAjRlV=->`Eib zh@s2}jZR!Ou#RMlo9hD5G!b{@g7h@ZL*>flXDObVmFmxSTHu%&2-_BNCt}X%cD~xVH=|6!9osfKI54eHZZe_)R@(aqEN_0b4-US zZK(*ONnOcOgqTG}ny!(KWdOc%HOO!=VTv>`i7_D=qVm}aSs_pjTG?`#z03chXYen4PbQQD&y{BehBD_ z#9HQv8JBcsMhWqerB{ZQ` zNIGXDmMUNoTRR4BH=(#i%K*r;XvIo_po@K8{3A|g{31<@2$t-!goiR2PYlSN?9B2I zk=VFeK1fbj!qGZ$IHs!1aRlbVAfE?XJW%M4vsd_|dE+)aG7$kDb#zy4&chtncPW-y z2y}OxQ7)o2wwQ_?6POd26iJt?DF_V>JVAOcP-KYyBg!P==i+4kTEmIiy-SI)9k#)6 zg#y^MSFQtwnt;q^aPrp=dNf078kHn&f?a92LXz-2yFxOis?%a(%VwoAZR&3H=a|R! zOYc;`rYMpi+l{gbuC=86idX22Q;J*fC0aQiXGD5B>eAwAY28X|;T z;)y}4E}RHq@QX8F$!z7yZ8_yhvoi_MZ5SwZapA{{SYk~3X`JbMr%FxF@qoye?1P+) zoGTyDlVn$8waqdr(RD;JVi-^=LEu+` tt|y9TkuGjnW Date: Fri, 22 May 2026 10:30:25 +0200 Subject: [PATCH 7/7] create directories for speibase files --- R/data_speibase.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/data_speibase.R b/R/data_speibase.R index d82090f..cf53ac4 100644 --- a/R/data_speibase.R +++ b/R/data_speibase.R @@ -213,6 +213,7 @@ read_speibase <- function(interval = 6, config = pg_current_config()) { spei_interval) if(!file.exists(out_path)){ + dir.create(dirname(out_path), recursive = TRUE, showWarnings = FALSE) # Calculate SPEI. This is a parallel process using snowfall. cru_pet_gz <- get_pgfile( source_name = "CRU Climate pet",