Skip to content

Commit a48ee8e

Browse files
dfkaprauntjzurlinshapiromatron
authored
CRAN Revisions 5 (#32)
* Modified 'DESCRIPTION' to comply with CRAN requirements. Started modifications to 'compileModel.R' and 'createModel.R'. * Change default compilation location to tmp directory. Use writeTmp=T to write compilation files to temp directory and use writeTmp=F to write compilation files to same directory as .model file * Added 'Free Software Foundation, Inc.' with role 'cph' to 'Authors' field in file 'DESCRIPTION'. * Copy whole file to tmp as opposed copying contents of file. Issue with End of Line (EOL) characters caused problems in Windows * Add missing comma in DESCRIPTION * Suppress console prints from C code * Made minor revisions to 'MCSim_model.R' and 'createModel.R'. Updated vignettes to reflect new default behavior for saving model output files and to remove the (now unnecssaary) calls to the 'cleanup()' method. * Added various error checking features. Still working on making mod translator output available when there is an error in translation. * Revised 'compileModel.R' to ensure that problems with MCSim model text translation are logged and appropriate error message is provided. * Used styler to ensure proper formatting of 'compileModel.R'. * Revised 'compileModel.R' to ensure the C compiler output is captured and logged. * Applied styler to correct formatting of 'compileModel.R'. * add tests * Made minor revisions to 'compileModel.R' and 'test-compileModel.R'. --------- Co-authored-by: AA\tzurlind <[email protected]> Co-authored-by: Andy Shapiro <[email protected]>
1 parent 8c13886 commit a48ee8e

15 files changed

+136
-65
lines changed

DESCRIPTION

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
Package: MCSimMod
2-
Title: An 'R' Package for Working with 'MCSim' Models
2+
Title: Working with 'MCSim' Models
33
Version: 0.9
44
Authors@R: c(
55
person("Dustin F.", "Kapraun", role=c("aut", "cre"), email = "[email protected]", comment = c(ORCID = "0000-0001-5570-6383")),
66
person("Todd J.", "Zurlinden", role="aut", comment = c(ORCID = "0000-0003-1372-3913")),
77
person("Andrew J.", "Shapiro", role="aut", comment = c(ORCID = "0000-0002-5233-8092")),
88
person("Ryan D.", "Friese", role="aut", comment = c(ORCID = "0000-0002-4121-2195")),
9-
person("Frederic Y.", "Bois", role="ctb", comment = c(ORCID = " 0000-0002-4154-0391"))
9+
person("Frederic Y.", "Bois", role="ctb", comment = c(ORCID = " 0000-0002-4154-0391")),
10+
person("Free Software Foundation, Inc.", role="cph")
1011
)
11-
Description: Tools that facilitate ordinary differential equation (ODE) modeling in 'R'. This package allows one to perform simulations for ODE models that are encoded in the GNU 'MCSim' model specification language using ODE solvers from the 'R' package 'deSolve'.
12+
Description: Tools that facilitate ordinary differential equation (ODE) modeling in 'R'. This package allows one to perform simulations for ODE models that are encoded in the GNU 'MCSim' model specification language (Bois, 2009) <doi:10.1093/bioinformatics/btp162> using ODE solvers from the 'R' package 'deSolve' (Soetaert et al., 2010) <doi:10.18637/jss.v033.i09>.
1213
Depends:
1314
methods,
1415
tools

R/MCSim_model.R

+16-2
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,36 @@ Model <- setRefClass("Model",
3131
#' @field parms Named vector of parameter values for the associated MCSim model.
3232
#' @field Y0 Named vector of initial conditions for the state variables of the associated MCSim model.
3333
#' @field paths List of character strings that are names of files associated with the model.
34+
#' @field writeTemp Boolean specifying whether to write model files to a temporary directory. If value is TRUE, model files will be Written to a temporary directory; if value is FALSE, model files will be Written to the same directory that contains the model specification file.
3435
mName = "character", mString = "character", initParms = "function",
3536
initStates = "function", Outputs = "ANY", parms = "numeric", Y0 = "numeric",
36-
paths = "list"
37+
paths = "list", writeTemp = "logical"
3738
),
3839
methods = list(
3940
initialize = function(...) {
4041
"Initialize the Model object using an MCSim model specification file (mName) or an MCSim model specification string (mString)."
4142
callSuper(...)
43+
if (length(mName) == 0 & length(mString) == 0) {
44+
stop("To create a Model object, supply either a file name (mName) or a model specification string (mString).")
45+
}
4246
if (length(mName) > 0 & length(mString) > 0) {
4347
stop("Cannot create a Model object using both a file name (mName) and a model specification string (mString). Provide only one of these arguments.")
4448
}
4549
if (length(mString) > 0) {
50+
if (writeTemp == FALSE) {
51+
stop("The value of writeTemp must be TRUE when creating a Model object using a model specification string (mstring).")
52+
}
4653
file <- tempfile(pattern = "mcsimmod_", fileext = ".model")
4754
writeLines(mString, file)
4855
} else {
49-
file <- normalizePath(paste0(mName, ".model"))
56+
if (writeTemp == TRUE) {
57+
source_file <- normalizePath(paste0(mName, ".model"))
58+
temp_directory <- tempdir()
59+
file <- file.path(temp_directory, basename(source_file))
60+
file_copied <- file.copy(from = source_file, to = file)
61+
} else {
62+
file <- normalizePath(paste0(mName, ".model"))
63+
}
5064
}
5165
mList <- .fixPath(file)
5266
mName <<- mList$mName

R/compileModel.R

+60-9
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#' @param dll_name Name of a DLL or SO file without the extension (".dll" or ".so").
1010
#' @param dll_file Name of the same DLL or SO file with the appropriate extension (".dll" or ".so").
1111
#' @param hash_file Name of a file containing a hash key for determining if `model_file` has changed since the previous translation and compilation.
12-
#'
12+
#' @returns No return value. Creates files and saves them in locations specified by function arguments.
1313
#' @import tools
1414
#' @useDynLib MCSimMod, .registration=TRUE
1515
#' @export
@@ -19,23 +19,74 @@ compileModel <- function(model_file, c_file, dll_name, dll_file, hash_file = NUL
1919
dyn.unload(dll_file)
2020
}
2121

22+
# Create a text connection to store output messages generated during the
23+
# translation from MCSim model specification text to C.
24+
text_conn <- textConnection("mod_output", open = "w")
25+
2226
# Create a C model file (ending with ".c") and an R parameter
2327
# initialization file (ending with "_inits.R") from the GNU MCSim model
24-
# definition file (ending with ".model"). Using the "-R" option generates
25-
# code compatible with functions in the R deSolve package.
28+
# specification file (ending with ".model"). Write translator output to the
29+
# text connection.
30+
sink(text_conn)
31+
.C("c_mod", model_file, c_file)
32+
sink()
33+
close(text_conn)
34+
mod_output <- paste(mod_output, collapse = "\n")
2635

27-
# if (.C("c_mod", model_file, c_file)[[1]] < 0) {
28-
if (is.null(.C("c_mod", model_file, c_file)[[2]])) {
29-
stop("c_mod failed")
36+
# Check to see if there was an error during translation. If so, save the
37+
# translator output to a file, print a message about its location, and stop
38+
# execution.
39+
if (grepl("*** Error:", mod_output, fixed = TRUE)) {
40+
temp_directory <- tempdir()
41+
out_file <- file.path(temp_directory, "mod_output.txt")
42+
write(mod_output, file = out_file)
43+
stop(
44+
"An error was identified when translating the MCSim model specification ",
45+
"text to C. Full details are available in the file ",
46+
normalizePath(out_file), "."
47+
)
3048
}
3149

32-
# Compile the C model to obtain "mName_model.o" and "mName_model.dll".
50+
# Check to see if there was a warning during translation. If so, save the
51+
# translator output to a file, print a message about its location, and raise a
52+
# warning.
53+
if (grepl("*** Warning:", mod_output, fixed = TRUE)) {
54+
temp_directory <- tempdir()
55+
out_file <- file.path(temp_directory, "mod_output.txt")
56+
write(mod_output, file = out_file)
57+
warning(
58+
"A warning was identified when translating the MCSim model ",
59+
"specification text to C. Full details are available in the file ",
60+
normalizePath(out_file), "."
61+
)
62+
}
63+
64+
# Compile the C model to obtain an object file (ending with ".o") and a
65+
# machine code file (ending with ".dll" or ".so"). Write compiler output
66+
# to a character string.
3367
r_path <- file.path(R.home("bin"), "R")
34-
system(paste0(r_path, " CMD SHLIB ", c_file))
68+
compiler_output <- system(paste(
69+
shQuote(r_path), "CMD SHLIB",
70+
shQuote(c_file)
71+
), intern = TRUE)
72+
73+
# Save the compiler output to a file and print a message about its location.
74+
temp_directory <- tempdir()
75+
out_file <- file.path(temp_directory, "compiler_output.txt")
76+
write(compiler_output, file = out_file)
77+
message(
78+
"C compilation complete. Full details are available in the file ",
79+
normalizePath(out_file), "."
80+
)
3581

82+
# If hash file name was provided, create a hash (md5 sum) for the model file
83+
# and print a message about its location.
3684
if (!is.null(hash_file)) {
3785
file_hash <- as.character(md5sum(model_file))
3886
write(file_hash, file = hash_file)
39-
cat("Hash calculated and saved to", hash_file, "\n")
87+
message(
88+
"Hash created and saved in the file ", normalizePath(hash_file),
89+
"."
90+
)
4091
}
4192
}

R/createModel.R

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
#'
2424
#' @param mName Name of an MCSim model specification file, excluding the file name extension `.model`.
2525
#' @param mString A character string containing MCSim model specification text.
26+
#' @param writeTemp Boolean specifying whether to write model files to a temporary directory. If value is TRUE (the default), model files will be Written to a temporary directory; if value is FALSE, model files will be Written to the same directory that contains the model specification file.
27+
#' @returns Model object.
2628
#' @export
27-
createModel <- function(mName = character(0), mString = character(0)) {
28-
return(Model(mName = mName, mString = mString))
29+
createModel <- function(mName = character(0), mString = character(0), writeTemp = TRUE) {
30+
return(Model(mName = mName, mString = mString, writeTemp = writeTemp))
2931
}

man/Model-class.Rd

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/compileModel.Rd

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/createModel.Rd

+6-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-compileModel.R

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
testthat::test_that("compileModel::error", {
2+
modelString <- "bad model"
3+
model <- createModel(mString = modelString)
4+
testthat::expect_error(
5+
model$loadModel(),
6+
"An error was identified when translating the MCSim model specification"
7+
)
8+
})
9+
10+
testthat::test_that("compileModel::warning", {
11+
# defining the input Bin as a dynamic will trigger a warning
12+
modelString <- "
13+
States = {A};
14+
Outputs = {Bout, Cout};
15+
Inputs = {Bin, Cin};
16+
A0 = 1e-6;
17+
r = 1.4;
18+
19+
Initialize {
20+
A = A0;
21+
}
22+
23+
Dynamics {
24+
Bin = 2;
25+
Bout = Bin;
26+
Cout = Cin;
27+
dt(A) = r * A;
28+
}
29+
30+
End.
31+
"
32+
33+
model <- createModel(mString = modelString)
34+
testthat::expect_warning(
35+
model$loadModel(),
36+
"A warning was identified when translating the MCSim model specification"
37+
)
38+
})

vignettes/events_demo.Rmd

-8
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,3 @@ plot(out[, "time"], out[, "C"],
134134
xlab = "Time (h)", ylab = "Concentration (mg/L)"
135135
)
136136
```
137-
138-
## Removing Output Files
139-
140-
We can remove output files that were created when building the model (i.e., files with names ending in ".c", ".o", "_inits.R", and ".dll" or ".so") by calling the `cleanup()` method.
141-
```{r, results='hide'}
142-
# Remove output files that were created when building the model.
143-
pk1_mod$cleanup()
144-
```

vignettes/exponential_demo.Rmd

+1-9
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ exp_mod_name <- file.path(mod_path, "exponential")
101101
exp_mod <- createModel(exp_mod_name)
102102
```
103103

104-
Once the model object is created, we can "load" the model (so that it's ready for use in a given R session) as follows. If necessary (e.g., when the model has not previously been "built"), this step will create output files (with names ending in ".c", ".o", "_inits.R", and ".dll" or ".so") in the same directory that contains the model specification file (with a name ending in ".model"). Some of these model files (the ones with names ending in "_inits.R" and ".dll" or ".so") are used to perform simulations with the model.
104+
Once the model object is created, we can "load" the model (so that it's ready for use in a given R session) as follows. If necessary (e.g., when the model has not previously been "built"), this step will create output files (with names ending in ".c", ".o", "_inits.R", and ".dll" or ".so") in a temporary directory. Some of these model files (the ones with names ending in "_inits.R" and ".dll" or ".so") are used to perform simulations with the model.
105105
```{r, results='hide'}
106106
# Load the model.
107107
exp_mod$loadModel()
@@ -153,11 +153,3 @@ plot(out[, "time"], out[, "A"],
153153
xlab = "Time", ylab = "Amount"
154154
)
155155
```
156-
157-
## Removing Output Files
158-
159-
We can remove output files that were created when building the model (i.e., files with names ending in ".c", ".o", "_inits.R", and ".dll" or ".so") by calling the `cleanup()` method.
160-
```{r, results='hide'}
161-
# Remove output files that were created when building the model.
162-
exp_mod$cleanup()
163-
```

vignettes/inputs_demo.Rmd

-8
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,3 @@ legend("topright",
140140
)
141141
```
142142
Note that for the "varying body mass" simulation, the increase in body mass had a diluting effect on concentration. That is, concentrations tended to be less for the "varying body mass" scenario than for the "constant body mass" scenario because increases in body mass ($M$) and corresponding increases in volume of distribution ($V_\textrm{d}$) caused concentration ($C$) to decrease more rapidly than would be the case for a constant body mass scenario in which clearance processes alone effect reductions in concentration.
143-
144-
## Removing Output Files
145-
146-
We can remove output files that were created when building the model (i.e., files with names ending in ".c", ".o", "_inits.R", and ".dll" or ".so") by calling the `cleanup()` method.
147-
```{r, results='hide'}
148-
# Remove output files that were created when building the model.
149-
pk1_mod$cleanup()
150-
```

vignettes/newt_cool_demo.Rmd

-8
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,3 @@ legend("topright", c("Tea", "Ambient Air"),
108108
lwd = c(2, 2)
109109
)
110110
```
111-
112-
## Removing Output Files
113-
114-
We can remove output files that were created when building the model (i.e., files with names ending in ".c", ".o", "_inits.R", and ".dll" or ".so") by calling the `cleanup()` method.
115-
```{r, results='hide'}
116-
# Remove output files that were created when building the model.
117-
newt_mod$cleanup()
118-
```

vignettes/pk1.png

36.9 KB
Loading

vignettes/pk1_demo.Rmd

+2-8
Original file line numberDiff line numberDiff line change
@@ -159,16 +159,10 @@ lines(out_IV[, "time"], out_IV[, "C"], lty = 2, lwd = 2)
159159
legend("topright", c("Oral", "IV"), lty = c(1, 2), lwd = 2)
160160
```
161161

162+
## Comparing AUC Values for Oral and IV Dosing Scenarios
163+
162164
Because the PK model we're using assumes that 100% of the substance in the exposure compartment (i.e., $A_0$) will eventually be transferred to the central compartment (i.e., 100% bioavailability for the oral exposure scenario) and 100% of an IV dose is delivered directly to the central compartment, the AUCs (at $t = \infty$) for the oral and IV exposure scenarios should be equal. We can verify that the AUCs at $t = 20$ hours (by which time most of the substance has been cleared) for both scenarios are approximately equal by examining the value of the $\textrm{AUC}$ output variable in the final row of the respective output matrices.
163165
```{r}
164166
out_oral[nrow(out_oral), "AUC"]
165167
out_IV[nrow(out_IV), "AUC"]
166168
```
167-
168-
## Removing Output Files
169-
170-
We can remove output files that were created when building the model (i.e., files with names ending in ".c", ".o", "_inits.R", and ".dll" or ".so") by calling the `cleanup` method.
171-
```{r, results='hide'}
172-
# Remove output files that were created when building the model.
173-
pk1_mod$cleanup()
174-
```

vignettes/quickstart.Rmd

-7
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,3 @@ plot(out[, "time"], out[, "y"],
7777
ylab = "y"
7878
)
7979
```
80-
81-
We can remove output files that were created when building the model (i.e., files with names ending in ".c", ".o", "_inits.R", and ".dll" or ".so") by calling the `cleanup()` method. Using the argument `deleteModel = TRUE` causes the model file (with name ending in ".model") that was created from the model string to also be deleted.
82-
83-
```{r, results='hide'}
84-
# Remove temporary files that were created when building the model.
85-
model$cleanup(deleteModel = TRUE)
86-
```

0 commit comments

Comments
 (0)