|
| 1 | +#' Parse completion time from a .complete file |
| 2 | +#' |
| 3 | +#' @param file Path to .complete file. |
| 4 | +#' @return POSIXct time or NA if parsing fails. |
| 5 | +#' @keywords internal |
| 6 | +#' @importFrom lubridate parse_date_time |
| 7 | +parse_complete_time <- function(file) { |
| 8 | + if (!file.exists(file)) return(as.POSIXct(NA)) |
| 9 | + tm <- tryCatch(readLines(file, n = 1L, warn = FALSE), error = function(e) NULL) |
| 10 | + if (is.null(tm) || length(tm) == 0L) return(as.POSIXct(NA)) |
| 11 | + parsed <- suppressWarnings(lubridate::parse_date_time(tm[1L], orders = c("mdy@HM", "mdy@HMS", "ymd HMS", "ymd HM", "mdy HM", "mdy HMS"))) |
| 12 | + if (length(parsed) == 0L || is.na(parsed[1L])) return(as.POSIXct(NA)) |
| 13 | + as.POSIXct(parsed) |
| 14 | +} |
| 15 | + |
| 16 | +#' Get processing status for a single subject |
| 17 | +#' |
| 18 | +#' @param scfg Study configuration list. |
| 19 | +#' @param sub_id Subject identifier. |
| 20 | +#' @param ses_id Optional session identifier. When `NULL`, all sessions found in the log directory are returned. |
| 21 | +#' @return A data.frame with columns indicating completion status and times for each enabled step. |
| 22 | +#' @export |
| 23 | +#' @importFrom checkmate assert_class assert_string |
| 24 | +get_subject_status <- function(scfg, sub_id, ses_id = NULL) { |
| 25 | + checkmate::assert_class(scfg, "bg_project_cfg") |
| 26 | + checkmate::assert_string(sub_id) |
| 27 | + checkmate::assert_string(ses_id, null.ok = TRUE) |
| 28 | + |
| 29 | + steps <- c() |
| 30 | + if (isTRUE(scfg$bids_conversion$enable)) steps <- c(steps, "bids_conversion") |
| 31 | + if (isTRUE(scfg$mriqc$enable)) steps <- c(steps, "mriqc") |
| 32 | + if (isTRUE(scfg$fmriprep$enable)) steps <- c(steps, "fmriprep") |
| 33 | + if (isTRUE(scfg$aroma$enable)) steps <- c(steps, "aroma") |
| 34 | + if (isTRUE(scfg$postprocess$enable)) steps <- c(steps, "postprocess") |
| 35 | + |
| 36 | + pp_streams <- if ("postprocess" %in% steps) get_postprocess_stream_names(scfg) else character(0) |
| 37 | + |
| 38 | + log_dir <- scfg$metadata$log_directory |
| 39 | + sub_log_dir <- file.path(log_dir, paste0("sub-", sub_id)) |
| 40 | + comp_files <- list.files(sub_log_dir, pattern = "_complete$", full.names = FALSE) |
| 41 | + ses_ids <- if (!is.null(ses_id)) ses_id else { |
| 42 | + sids <- unique(sub("^.*_ses-([^_]+)_complete$", "\\1", comp_files[grepl("_ses-", comp_files)])) |
| 43 | + sids <- sids[!is.na(sids) & sids != "^.*_ses-([^_]+)_complete$"] |
| 44 | + if (length(sids) == 0) NA_character_ else sids |
| 45 | + } |
| 46 | + |
| 47 | + res <- lapply(ses_ids, function(ss) { |
| 48 | + row <- list(sub_id = sub_id, ses_id = ifelse(is.na(ss), NA_character_, ss)) |
| 49 | + for (st in steps) { |
| 50 | + if (st != "postprocess") { |
| 51 | + chk <- is_step_complete(scfg, sub_id, ses_id = if (st == "bids_conversion" && !is.na(ss)) ss else NULL, step_name = st) |
| 52 | + row[[paste0(st, "_complete")]] <- chk$complete |
| 53 | + row[[paste0(st, "_time")]] <- if (chk$complete) parse_complete_time(chk$complete_file) else as.POSIXct(NA) |
| 54 | + } else { |
| 55 | + for (stream in pp_streams) { |
| 56 | + chk <- is_step_complete(scfg, sub_id, ses_id = if (!is.na(ss)) ss else NULL, step_name = "postprocess", pp_stream = stream) |
| 57 | + row[[paste0(stream, "_complete")]] <- chk$complete |
| 58 | + row[[paste0(stream, "_time")]] <- if (chk$complete) parse_complete_time(chk$complete_file) else as.POSIXct(NA) |
| 59 | + } |
| 60 | + } |
| 61 | + } |
| 62 | + row |
| 63 | + }) |
| 64 | + |
| 65 | + df <- do.call(rbind.data.frame, res) |
| 66 | + class(df) <- c("bg_status_df", class(df)) |
| 67 | + df |
| 68 | +} |
| 69 | + |
| 70 | +#' Get processing status for all subjects |
| 71 | +#' |
| 72 | +#' @param scfg Study configuration list. |
| 73 | +#' @return Data.frame with one row per subject/session containing completion status columns. |
| 74 | +#' @export |
| 75 | +#' @importFrom checkmate assert_class |
| 76 | +get_project_status <- function(scfg) { |
| 77 | + checkmate::assert_class(scfg, "bg_project_cfg") |
| 78 | + log_dir <- scfg$metadata$log_directory |
| 79 | + sub_dirs <- list.dirs(log_dir, recursive = FALSE, full.names = FALSE) |
| 80 | + sub_ids <- sub("^sub-", "", sub_dirs[grepl("^sub-", sub_dirs)]) |
| 81 | + res <- lapply(sub_ids, function(id) get_subject_status(scfg, id)) |
| 82 | + df <- do.call(rbind.data.frame, res) |
| 83 | + class(df) <- c("bg_status_df", class(df)) |
| 84 | + df |
| 85 | +} |
| 86 | + |
| 87 | +#' Summarize project status |
| 88 | +#' |
| 89 | +#' @param object A data.frame produced by `get_project_status()`. |
| 90 | +#' @return Data.frame summarizing number of subjects completed for each step. |
| 91 | +#' @export |
| 92 | +summary.bg_status_df <- function(object, ...) { |
| 93 | + step_cols <- grep("_complete$", names(object), value = TRUE) |
| 94 | + counts <- vapply(step_cols, function(x) sum(object[[x]], na.rm = TRUE), numeric(1)) |
| 95 | + data.frame(step = step_cols, n_complete = counts, row.names = NULL, stringsAsFactors = FALSE) |
| 96 | +} |
| 97 | + |
0 commit comments