diff --git a/DESCRIPTION b/DESCRIPTION index 57676cd35cd674aa70876a60dbdb8c5fa8c88beb..f4d231d948582695e2d232ba6ecff81ec9210475 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -46,6 +46,7 @@ Roxygen: list(markdown = TRUE) Collate: 'base.R' 'resources.R' + 'errors.R' 'mix.R' 'state.R' 'plotting.R' diff --git a/R/api.R b/R/api.R index 1b2db95a21a47e1f7f6ea99725f5176fa8de8c18..e1586a471c992e06beafb2d7bded99faa1656295 100644 --- a/R/api.R +++ b/R/api.R @@ -684,16 +684,12 @@ prepare_app <- function(dir_before, init$projects <- norm_path(projects) init$metfrag_db_dir <- if (nchar(norm_path(metfrag_db_dir))>0L) norm_path(metfrag_db_dir) else "" init$metfrag_runtime <- if (nchar(norm_path(metfrag_runtime))>0L) norm_path(metfrag_runtime) else "" - if (!dir.exists(init$top_data_dir)) stop(errorCondition(paste0("Data directory (top_data_dir), currently `", - init$top_data_dir, - "` does not exist. Abort."), - class = "top-data-dir-absent")) - if (!dir.exists(init$projects)) stop(errorCondition(paste0("User root directory (projects), currently `", - init$projects,"` does not exist.. Abort."), - class= "projects-absent")) - - if (nchar(init$metfrag_db_dir)>0L && !dir.exists(init$metfrag_db_dir)) stop(errorCondition("MetFrag DB directory specified, but cannot be found.", class = "mf-db-dir-absent")) - if (nchar(init$metfrag_runtime)>0L && !file.exists(init$metfrag_runtime)) stop(errorCondition("MetFrag jar file specified, but cannot be found.", class = "mf-jar-absent")) + + if (!dir.exists(init$top_data_dir)) stop(errc_top_data_dir_absent) + if (!dir.exists(init$projects)) stop(errc_projects_absent) + + if (nchar(init$metfrag_db_dir)>0L && !dir.exists(init$metfrag_db_dir)) stop(errc_mf_db_dir_absent) + if (nchar(init$metfrag_runtime)>0L && !file.exists(init$metfrag_runtime)) stop(errc_mf_jar_absent) dir_start <- tempfile("shinyscreen") dir.create(dir_start, recursive = T) diff --git a/R/errors.R b/R/errors.R new file mode 100644 index 0000000000000000000000000000000000000000..d3fe162dca8d7c6418c771b2baad5ef48748cbad --- /dev/null +++ b/R/errors.R @@ -0,0 +1,23 @@ +## Copyright (C) 2020,2021,2023 by University of Luxembourg + +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at + +## http://www.apache.org/licenses/LICENSE-2.0 + +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. + +errc_mf_jar_absent = errorCondition("MetFrag jar file specified, but cannot be found.", class = "mf-jar-absent") +errc_mf_db_dir_absent = errorCondition("MetFrag DB directory specified, but cannot be found.", class = "mf-db-dir-absent") +errc_mf_db_file_absent = errorCondition("MetFrag DB file specified, but cannot be found.", class = "mf-db-dir-absent") + +errc_projects_absent = errorCondition("User root directory (projects), currently does not exist.. Abort.", class= "projects-absent") +errc_top_data_dir_absent = errorCondition("Data directory (top_data_dir) does not exist. Abort.", + class = "top-data-dir-absent") + +errc_conf_file_absent <- errorCondition("There is no config file in the project directory.",class="conf-file-absent") diff --git a/R/state.R b/R/state.R index 7bdb5b05ef5b1c47394cd9d24a4bfdda565d0446..38875f1b94770562d167170bec53bd97e9e13dfd 100644 --- a/R/state.R +++ b/R/state.R @@ -1,4 +1,4 @@ -## Copyright (C) 2020,2021 by University of Luxembourg +## Copyright (C) 2020,2021,2023 by University of Luxembourg ## Licensed under the Apache License, Version 2.0 (the "License"); ## you may not use this file except in compliance with the License. @@ -12,8 +12,22 @@ ## See the License for the specific language governing permissions and ## limitations under the License. +init_state <- function(m) { + m$out$tab = list() + m$input$datafiles = NULL + m$input$tab$mzml = EMPTY_MZML + lab = gen_uniq_lab(list(),pref="L") + m$input$tab$lists = list() + m$input$tab[[lab[[1]]]] = EMPTY_CMPD_LIST + m$out$tab$comp = EMPTY_COMP_TAB + m +} -##' @export +#' @title Create Initial State +#' @details Creates an initial, bare state. +#' @return A state object. +#' @export +#' @author Todor Kondić new_state <- function() { m <- new_conf() init_state(m) @@ -55,25 +69,57 @@ reinit_run_data <- function(projects,top_data_dir,project,run=NULL) { run } +is_metfrag_available <- function(conf) { + rtime = conf$metfrag$runtime + dbpath = conf$metfrag$db_path -## This helps decouple "cross-platform" configuration from the -## (file-)system dependent facts. -##' @export + if (nchar(rtime)==0L && nchar(dbpath)==0L) return(F) + if (!file.exists(rtime)) stop(errc_mf_jar_absent) + if (!file.exists(dbpath)) stop(errc_mf_db_file_absent) + T +} + +#' @title Create Runtime Configuration +#' @details This is a part of the configuration that can only be +#' diagnosed at runtime. +#' @param project `character(1)`, project title (and the directory name under `projects`) +#' @param conf `conf`, configuration object, optional +#' @return `run` substate +#' @author Todor Kondić +#' @export new_runtime_state <- function(project,conf=NULL) { if (!is.character(project)) stop("Argument `project' must be a character string.") if (!dir.exists(project)) stop('Project directory either does not exist, or is unreadable.') - project_path <- norm_path(project) - project <- basename(project) - run <- list() - run$project <- project - run$paths$project <- project_path + project_path = norm_path(project) + project = basename(project) + run = list() + run$project = project + run$paths$project = project_path + + if (is.null(conf)) { + run$metfrag$available = F + } else { + run$metfrag$available = is_metfrag_available(conf) + } - run$paths$data <- if (is.null(conf$paths$data)) { - project_path - } else { - run$paths$data <- norm_path(conf$paths$data) - } + if (run$metfrag$available) { + mfdir = file.path(run$paths$project,"metfrag") + dir.create(mfdir) + dir.create(file.path(mfdir,"results")) + dir.create(file.path(mfdir,"config")) + dir.create(file.path(mfdir,"spec")) + dir.create(file.path(mfdir,"log")) + run$metfrag$path=mfdir + } + + + run$paths$data = if (is.null(conf$paths$data)) { + project_path + } else { + norm_path(conf$paths$data) + } + if (!dir.exists(run$paths$data)) stop("Path to data directory either does not exist, or is inaccesible.") @@ -89,16 +135,23 @@ new_empty_project <- function(project) { } ##' @export +##' @title Create a New Project +##' @param project `character(1)`, path to a directory containing all the projects +##' @param datatab `datatab`, a `data.table` describing data files, optional +##' @param conf `conf`, a configuration object, optional +##' @author Todor Kondić new_project <- function(project,datatab=NULL,conf=NULL) { - m <- new_state() - m$run <- new_runtime_state(project) - fn_conf <- file.path(m$run$paths$project,FN_CONF) - m$conf <- if (is.null(conf)) {yaml::yaml.load_file(fn_conf)} else conf - m$conf$compounds$lists <- label_cmpd_lists(m$conf$compounds$lists) - m$run <- new_runtime_state(project,conf=m$conf) - + m = new_state() + m$run = new_runtime_state(project) + fn_conf = file.path(m$run$paths$project,FN_CONF) + m$conf = if (is.null(conf)) { + if (!file.exists(fn_conf)) stop(errc_conf_file_absent) + yaml::yaml.load_file(fn_conf) + } else conf + m$conf$compounds$lists = label_cmpd_lists(m$conf$compounds$lists) + m$run = new_runtime_state(project,conf=m$conf) if (!is.null(datatab)) { - m$input$tab$mzml <- datatab + m$input$tab$mzml = datatab } m @@ -188,18 +241,8 @@ get_fn_ftab <- function(m) { file.path(m$run$paths$project, FN_DATA_TAB) } -init_state <- function(m) { - m$out$tab <- list() - m$input$datafiles <- NULL - m$input$tab$mzml <- EMPTY_MZML - lab <- gen_uniq_lab(list(),pref="L") - m$input$tab$lists <- list() - m$input$tab[[lab[[1]]]] <- EMPTY_CMPD_LIST - m$out$tab$comp <- EMPTY_COMP_TAB - m -} - base_conf <- function () { + ## Base state. m <- list() m$conf <- list(project=NA_character_, compounds=list(lists=list(), @@ -209,6 +252,7 @@ base_conf <- function () { } extr_conf <- function(m) { + ## Extraction defaults. m$conf$tolerance <- list("ms1 coarse"=MS1_ERR_COARSE, "ms1 fine"=MS1_ERR_FINE, "eic"=EIC_ERR, @@ -219,6 +263,7 @@ extr_conf <- function(m) { } presc_conf <- function(m) { + ## Prescreening defaults. m$conf$prescreen <- list("ms1_int_thresh"=MS1_INT_THOLD, "ms2_int_thresh"=MS2_INT_THOLD, "s2n"=MS1_SN_FAC, @@ -227,16 +272,25 @@ presc_conf <- function(m) { } fig_conf <- function(m) { + ## Plotting defaults. m$conf$figures$rt_min <- "NA_real_ min" m$conf$figures$rt_max <- "NA_real_ min" m$conf$figures$ext <- "pdf" m } -new_conf <- function() fig_conf( - presc_conf( - extr_conf( - base_conf()))) +metfrag_conf <- function(m) { + ## MetFrag configuration defaults. + m$conf$metfrag$runtime = "" + m$conf$metfrag$db_path = "" + m +} + +new_conf <- function() metfrag_conf( + fig_conf( + presc_conf( + extr_conf( + base_conf())))) encode_ms2_to_line <- function(ms2) { ## ms2 is a data.frame whose first column is mz and the second intensity. diff --git a/man/new_project.Rd b/man/new_project.Rd new file mode 100644 index 0000000000000000000000000000000000000000..f0e35d4460ac338e94052e9b126fd2dff16b3494 --- /dev/null +++ b/man/new_project.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/state.R +\name{new_project} +\alias{new_project} +\title{Create a New Project} +\usage{ +new_project(project, datatab = NULL, conf = NULL) +} +\arguments{ +\item{project}{\code{character(1)}, path to a directory containing all the projects} + +\item{datatab}{\code{datatab}, a \code{data.table} describing data files, optional} + +\item{conf}{\code{conf}, a configuration object, optional} +} +\description{ +Create a New Project +} +\author{ +Todor Kondić +} diff --git a/man/new_runtime_state.Rd b/man/new_runtime_state.Rd new file mode 100644 index 0000000000000000000000000000000000000000..80612a373bfd8fd081a34ad8d07e66462c04fd7d --- /dev/null +++ b/man/new_runtime_state.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/state.R +\name{new_runtime_state} +\alias{new_runtime_state} +\title{Create Runtime Configuration} +\usage{ +new_runtime_state(project, conf = NULL) +} +\arguments{ +\item{project}{\code{character(1)}, project title (and the directory name under \code{projects})} + +\item{conf}{\code{conf}, configuration object, optional} +} +\value{ +\code{run} substate +} +\description{ +Create Runtime Configuration +} +\details{ +This is a part of the configuration that can only be +diagnosed at runtime. +} +\author{ +Todor Kondić +} diff --git a/man/new_state.Rd b/man/new_state.Rd new file mode 100644 index 0000000000000000000000000000000000000000..40208002c585f6146b9e5ea9103fd79cc0110ec3 --- /dev/null +++ b/man/new_state.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/state.R +\name{new_state} +\alias{new_state} +\title{Create Initial State} +\usage{ +new_state() +} +\value{ +A state object. +} +\description{ +Create Initial State +} +\details{ +Creates an initial, bare state. +} +\author{ +Todor Kondić +} diff --git a/tests/testthat/test-state.R b/tests/testthat/test-state.R index 636fbe59c6bb30ad1daa21ce740be816a8bf9c8f..2c5ae485cc02871853761ad06babfe5e7de59859 100644 --- a/tests/testthat/test-state.R +++ b/tests/testthat/test-state.R @@ -1,3 +1,34 @@ +test_that("Test state creation",{ + + withr::with_tempdir({ + ## new_empty_project + ppath = file.path('test','project') + dir.create(ppath,recursive=T) + res = shinyscreen::new_empty_project(ppath) + testthat::expect_true(dir.exists(res$run$paths$project)) + testthat::expect_false(res$run$metfrag$available) + + ## new_project + testthat::expect_error(shinyscreen::new_project(ppath),class="conf-file-absent") + + ## Switch metfrag on when conditions met. + conf = res$conf + mf_jar = "bingo.jar" + saveRDS(" ",mf_jar) + mf_db = "bingo.csv" + saveRDS(" ",mf_db) + conf$metfrag$runtime = norm_path(mf_jar) + conf$metfrag$db_path = norm_path(mf_db) + testthat::expect_true(is_metfrag_available(conf)) + + yaml::write_yaml(conf,file.path(ppath,FN_CONF)) + x = shinyscreen::new_project(ppath) + testthat::expect_true(x$run$metfrag$available) + }) +}) + + + test_that("pack_ms2_w_summ",{ summ = STATE_DATA$out$tab$summ ms2 = STATE_DATA$extr$ms2 @@ -17,3 +48,4 @@ test_that("pack_ms2_w_summ",{ }) +