From 19d3344dd372993c053ef9d76099646e2ca724e5 Mon Sep 17 00:00:00 2001 From: dkapraun Date: Tue, 25 Nov 2025 15:44:27 -0500 Subject: [PATCH] Ensure that multiple different models can be used in the same R session. --- DESCRIPTION | 2 +- R/MCSim_model.R | 29 ++++++++++++++---- R/compileModel.R | 73 +++++++++++++++++++++++++++++++++++++++++++++- man/Model-class.Rd | 2 +- 4 files changed, 97 insertions(+), 9 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 257db47..56d9eed 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: MCSimMod Title: Working with 'MCSim' Models -Version: 1.1 +Version: 1.1.9000 Authors@R: c( person("Dustin F.", "Kapraun", role=c("aut", "cre"), email = "kapraun.dustin@epa.gov", comment = c(ORCID = "0000-0001-5570-6383")), person("Todd J.", "Zurlinden", role="aut", comment = c(ORCID = "0000-0003-1372-3913")), diff --git a/R/MCSim_model.R b/R/MCSim_model.R index 18a5c86..dca67ff 100644 --- a/R/MCSim_model.R +++ b/R/MCSim_model.R @@ -106,10 +106,24 @@ Model <- setRefClass("Model", # Run script that defines initialization functions. source(paths$inits_file, local = TRUE) - initParms <<- initParms - initStates <<- initStates - Outputs <<- Outputs + # Associate initParms for this model with the initParms function defined + # in inits_file. + r_command_string <- paste0("initParms <<- initParms_", mName) + r_expression <- parse(text = r_command_string) + eval(r_expression) + + # Associate initStates for this model with the initStates function defined + # in inits_file. + r_command_string <- paste0("initStates <<- initStates_", mName) + r_expression <- parse(text = r_command_string) + eval(r_expression) + + # Associate Outputs for this model with the Outputs variable defined in + # inits_file. + r_command_string <- paste0("Outputs <<- Outputs_", mName) + r_expression <- parse(text = r_command_string) + eval(r_expression) parms <<- initParms() Y0 <<- initStates(parms) @@ -125,10 +139,13 @@ Model <- setRefClass("Model", runModel = function(times, ...) { "Perform a simulation for the Model object using the \\code{deSolve} function \\code{ode} for the specified \\code{times}." # Solve the ODE system using the "ode" function from the package "deSolve". + derivs_name <- paste0("derivs_", mName) + initforc_name <- paste0("initforc_", mName) + initmod_name <- paste0("initmod_", mName) out <- ode(Y0, times, - func = "derivs", parms = parms, dllname = paths$dll_name, - initforc = "initforc", initfunc = "initmod", nout = length(Outputs), - outnames = Outputs, ... + func = derivs_name, parms = parms, dllname = paths$dll_name, + initforc = initforc_name, initfunc = initmod_name, + nout = length(Outputs), outnames = Outputs, ... ) # Return the simulation output. diff --git a/R/compileModel.R b/R/compileModel.R index ff6204a..cef24fd 100644 --- a/R/compileModel.R +++ b/R/compileModel.R @@ -16,7 +16,11 @@ #' @export compileModel <- function(model_file, c_file, dll_name, dll_file, hash_file = NULL, verbose_output = FALSE) { # Unload DLL if it has been loaded. - if (is.loaded("derivs", PACKAGE = dll_name)) { + mList <- .fixPath(model_file) + model_name <- mList$mName + model_path <- mList$mPath + derivs_name <- paste0("derivs_", model_name) + if (is.loaded(derivs_name, PACKAGE = dll_name)) { dyn.unload(dll_file) } @@ -92,6 +96,73 @@ compileModel <- function(model_file, c_file, dll_name, dll_file, hash_file = NUL } } + # Code to update C source file using model-specific names for objects. + + # Read the original C source file. + lines <- readLines(c_file) + + # Find and replace C object names with model-specific names. + item_to_replace <- c( + "parms", + "forc", + "Nout", + "nr", + "ytau", + "yini", + "lagvalue", + "CalcDelay", + "initmod", + "initforc", + "initState", + "getParms", + "derivs", + "jac", + "event", + "root" + ) + for (idx in seq(length(item_to_replace))) { + lines <- gsub( + paste0("\\b", item_to_replace[idx], "\\b"), + paste0(item_to_replace[idx], "_", model_name), + lines + ) + } + + # Overwrite the C source file with the updated text. + writeLines(lines, c_file) + + + # Code to update inits R source file using model-specific names for objects. + + # Get inits R source file name. + inits_file <- file.path( + model_path, + paste0(model_name, "_model_inits.R") + ) + + # Read the original inits R source file. + lines <- readLines(inits_file) + + # Find and replace R and C object names with model-specific names. + item_to_replace <- c( + "initParms", + "getParms", + "Outputs", + "initStates", + "initState" + ) + for (idx in seq(length(item_to_replace))) { + lines <- gsub( + paste0("\\b", item_to_replace[idx], "\\b"), + paste0(item_to_replace[idx], "_", model_name), + lines + ) + } + + # Overwrite the R inits source file with the updated text. + writeLines(lines, inits_file) + + # Compile the C model to obtain an object file (ending with ".o") and a # machine code file (ending with ".dll" or ".so"). Write compiler output # to a character string. diff --git a/man/Model-class.Rd b/man/Model-class.Rd index 83947f1..1925d91 100644 --- a/man/Model-class.Rd +++ b/man/Model-class.Rd @@ -65,6 +65,6 @@ expression \code{mod$updateParms()}. Use the \code{createModel()} function to cr \item{\code{updateParms(new_parms = NULL)}}{Update values of parameters for the Model object.} -\item{\code{updateY0(new_states = NULL)}}{Update values of initital conditions of state variables for the Model object.} +\item{\code{updateY0(new_states = NULL)}}{Update values of initial conditions of state variables for the Model object.} }}