Skip to content

Commit

Permalink
Cli commands in ospsuite r (#1483)
Browse files Browse the repository at this point in the history
* Add core from Open-Systems-Pharmacology/PK-Sim#2948

* Add functions to
- run simulations from snapshot files
- convert between snapshot and project files
+ Add tests
+ Add test snapshot and project

* add {cli} as dependency

* Add examples

* Allow exporting results to JSON file
+ prefix format with "export"

* Check arguments

* Better error handling

* Improve user feedback
+ formating

* Add News entries

* 🤖 Update Core Files.

* devtools::document()

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
Felixmil and github-actions[bot] authored Sep 9, 2024
1 parent 62caa92 commit 219502a
Show file tree
Hide file tree
Showing 29 changed files with 1,310 additions and 160 deletions.
2 changes: 2 additions & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Imports:
xml2,
openxlsx,
lifecycle,
cli,
showtext
Suggests:
pacman,
Expand Down Expand Up @@ -108,6 +109,7 @@ Collate:
'simulation-settings.R'
'simulation.R'
'snapshot-parameter.R'
'snapshots.R'
'solver-settings.R'
'utilities-path.R'
'standard-path.R'
Expand Down
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export(calculateResiduals)
export(clearMemory)
export(clearOutputIntervals)
export(clearOutputs)
export(convertSnapshot)
export(convertUnits)
export(createDistributions)
export(createImporterConfigurationForFile)
Expand Down Expand Up @@ -127,6 +128,7 @@ export(runSensitivityAnalysis)
export(runSimulation)
export(runSimulationBatches)
export(runSimulations)
export(runSimulationsFromSnapshot)
export(saveDataSetToPKML)
export(saveSimulation)
export(scaleParameterValues)
Expand Down
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# ospsuite (development version)

## Major Changes

- New `runSimulationsFromSnapshot()` to run simulations from `.json` snapshots files,
- New `convertSnapshot()` to convert project snapshots between `.json` and `.pksim5` files.

# ospsuite 12.1.0

## Major Changes
Expand Down
160 changes: 160 additions & 0 deletions R/snapshots.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#' Run Simulations From Snapshot Files
#'
#' @param ... character strings, path to snapshot files or a directory containing snapshot files
#' @param output character string, path to the output directory where to write simulation results
#' @param exportCSV logical, whether to export the results as csv (default = TRUE)
#' @param exportPKML logical, whether to export the results as pkml (default = FALSE)
#' @param exportJSON logical, whether to export simulation results as json (default = FALSE)
#' @param exportXML logical, whether to export the results as xml (default = FALSE)
#'
#' @return NULL
#' @export
#'
#' @examples
#' \dontrun{
#' runSimulationsFromSnapshot("path/to/my_snapshot.json", csv = TRUE, pkml = TRUE)
#' }
runSimulationsFromSnapshot <- function(..., output = ".", exportCSV = TRUE, exportPKML = FALSE, exportJSON = FALSE, exportXML = FALSE) {
ospsuite.utils::validateIsLogical(object = c(exportCSV, exportPKML, exportXML))
ospsuite.utils::validateIsCharacter(object = c(..., output))

paths_exist <- file.exists(c(..., output))
if (!all(paths_exist)) {
missing_paths <- c(..., output)[!paths_exist]
cli::cli_abort(message = c("x" = "Some of the paths provided do not exist: {.file {missing_paths}}"))
}

initPKSim()

temp_dir <- .gatherFiles(c(...))

JsonRunOptions <- rSharp::newObjectFromName("PKSim.CLI.Core.RunOptions.JsonRunOptions")
JsonRunOptions$set("InputFolder", temp_dir)
JsonRunOptions$set("OutputFolder", normalizePath(output))

if (isTRUE(exportJSON)) {
exportJSON <- 1L
} else {
exportJSON <- 0L
}
if (isTRUE(exportCSV)) {
exportCSV <- 2L
} else {
exportCSV <- 0L
}
if (isTRUE(exportXML)) {
exportXML <- 4L
} else {
exportXML <- 0L
}
if (isTRUE(exportPKML)) {
exportPKML <- 8L
} else {
exportPKML <- 0L
}

ExportMode <- exportJSON + exportCSV + exportXML + exportPKML
# 1: json
# 2: csv
# 3: json + csv
# 4: xml
# 5: xml + json
# 6: xml + csv
# 7: json + csv + xml
# 8: pkml
# 9: pkml + json
# 10: pkml + csv
# 11: pkml + json + csv
# 12: pkml + xml
# 13: pkml + xml + json
# 14: pkml + xml + csv
# 15: all

JsonRunOptions$set("ExportMode", ExportMode)

cli::cli_process_start(
msg = "Running simulations from {length(list.files(temp_dir))} snapshot{?s}",
msg_done = "Simulations completed",
msg_failed = "An error occured while running simulation"
)

tryCatch(
{
invisible(rSharp::callStatic("PKSim.R.Api", "RunJson", JsonRunOptions))
},
error = function(e) {
message <- stringr::str_extract(as.character(e), "(?<=Message: )[^\\n]*")

cli::cli_abort(message = message, call = rlang::caller_env(n = 4))
}
)
}

#' Convert between snapshot and project formats
#'
#' @param ... character strings, path to files or a directory containing files to convert
#' @param format, character string, target format either "snapshot" or "project".
#' @param output character string, path to the output directory where to write the converted files
#'
#' @return NULL
#' @export
#'
#' @examples
#' \dontrun{
#' convertSnapshot("path/to/snapshot.json", format = "project")
#' convertSnapshot("path/to/project.pksim5", format = "snapshot")
#' }
convertSnapshot <- function(..., format, output = ".") {
rlang::arg_match(arg = format, values = c("snapshot", "project"))

initPKSim()

temp_dir <- .gatherFiles(c(...))

SnapshotRunOptions <- rSharp::newObjectFromName("PKSim.CLI.Core.RunOptions.SnapshotRunOptions")
SnapshotRunOptions$set(name = "InputFolder", value = temp_dir)
SnapshotRunOptions$set(name = "OutputFolder", value = normalizePath(output))

if (format == "project") {
SnapshotRunOptions$set("ExportMode", 0L)
nfiles <- length(list.files(temp_dir, pattern = ".json"))
} else if (format == "snapshot") {
SnapshotRunOptions$set("ExportMode", 1L)
nfiles <- length(list.files(temp_dir, pattern = ".pksim5"))
}

cli::cli_process_start(
msg = "Converting {nfiles} files{?s} to {format} format",
msg_done = "Conversion completed",
msg_failed = "An error occured while converting files"
)

rSharp::callStatic("PKSim.R.Api", "RunSnapshot", SnapshotRunOptions)
}


#' Gather files and files from folders to one location
#'
#' @param ... character strings of file paths or folder paths
#'
#' @return A temporary directory with all files copied to it
.gatherFiles <- function(...) {
temp_dir <- tempfile()
dir.create(temp_dir)
for (element in c(...)) {
# if the element is a folder, list all files in it and copy them to the temp directory
if (dir.exists(element)) {
files <- list.files(element, full.names = TRUE, recursive = TRUE)
for (file in files) {
file.copy(from = file, to = temp_dir)
}
next
}
# if the element is a file, copy it to the temp directory
else if (file.exists(element)) {
file.copy(from = element, to = temp_dir)
next
}
}
return(temp_dir)
}
Loading

0 comments on commit 219502a

Please sign in to comment.