diff --git a/DESCRIPTION b/DESCRIPTION index 0bb57e46..023ee7b6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: mrgsolve Title: Simulate from ODE-Based Models -Version: 1.5.1.9001 +Version: 1.5.1.9002 Authors@R: c(person(given = "Kyle T", family = "Baron", role = c("aut", "cre"), diff --git a/Makefile b/Makefile index 590bc859..8b803501 100644 --- a/Makefile +++ b/Makefile @@ -78,6 +78,7 @@ readme: doc: Rscript -e "roxygen2::roxygenize()" +.PHONY: build build: R CMD build --md5 $(PKGDIR) --no-manual diff --git a/NAMESPACE b/NAMESPACE index 64b41012..1430f355 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -22,6 +22,7 @@ S3method(handle_spec_block,specBLOCK) S3method(handle_spec_block,specCAPTURE) S3method(handle_spec_block,specCMT) S3method(handle_spec_block,specCMTN) +S3method(handle_spec_block,specEVENT) S3method(handle_spec_block,specFIXED) S3method(handle_spec_block,specINCLUDE) S3method(handle_spec_block,specINIT) diff --git a/R/Aaaa.R b/R/Aaaa.R index 1d6ea302..9bfee4d2 100644 --- a/R/Aaaa.R +++ b/R/Aaaa.R @@ -80,7 +80,7 @@ block_list <- c("ENV", "PROB", "PARAM", "INIT", "PKMODEL", "PLUGIN", "INCLUDE", "NAMESPACE", "OMEGA", "SIGMA", "SET","GLOBAL", "CAPTURE", "PREAMBLE", "PRED", "BLOCK", "TRANSIT", "YAML", "NMEXT", - "INPUT") + "INPUT", "EVENT") Reserved_cvar <- c("SOLVERTIME","table","ETA","EPS", "AMT", "CMT", "ID", "TIME", "EVID","simeps", "self", "simeta", diff --git a/R/class_mrgmod.R b/R/class_mrgmod.R index a63e421a..d45a6ea8 100644 --- a/R/class_mrgmod.R +++ b/R/class_mrgmod.R @@ -16,8 +16,8 @@ # along with mrgsolve. If not, see . valid_funs <- function(x) { - x1 <- length(x)==4 - x2 <- identical(names(x), c("main", "ode", "table", "config")) + x1 <- length(x)==5 + x2 <- identical(names(x), c("main", "ode", "table", "event", "config")) if(x1 & x2) return(list(TRUE,NULL)) msg <- c( "Invalid functions specification.", @@ -794,7 +794,8 @@ parin <- function(x) { ss_n = 500, ss_fixed = FALSE, interrupt = -1, - etasrc = "omega" + etasrc = "omega", + call_event = x@shlib$call_event ) } diff --git a/R/compile.R b/R/compile.R index c08d0fa8..2fde0a9b 100644 --- a/R/compile.R +++ b/R/compile.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2023 Metrum Research Group +# Copyright (C) 2013 - 2024 Metrum Research Group # # This file is part of mrgsolve. # @@ -17,12 +17,15 @@ generate_rdefs <- function(pars, cmt, - func, - init_fun="", - table_fun="", - config_fun="", - model="",omats,smats, - set=list(), + func = "", + init_fun = "", + table_fun = "", + event_fun = "", + config_fun = "", + model = "", + omats, + smats, + set = list(), plugin = NULL, dbsyms = FALSE, ...) { @@ -91,6 +94,7 @@ generate_rdefs <- function(pars, c(paste0("#define __INITFUN___ ",init_fun), paste0("#define __ODEFUN___ ",func), paste0("#define __TABLECODE___ ", table_fun), + paste0("#define __EVENTFUN___ ", event_fun), paste0("#define __CONFIGFUN___ ", config_fun), paste0("#define __REGISTERFUN___ ", register_fun(model)), paste0("#define _nEQ ", ncmt), diff --git a/R/funset.R b/R/funset.R index 79b5c8c3..59e31d14 100644 --- a/R/funset.R +++ b/R/funset.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2019 Metrum Research Group, LLC +# Copyright (C) 2013 - 2024 Metrum Research Group # # This file is part of mrgsolve. # @@ -30,6 +30,7 @@ There was a problem accessing the model shared object. main_func <- function(x) x@funs["main"] ode_func <- function(x) x@funs["ode"] table_func <- function(x) x@funs["table"] +event_func <- function(x) x@funs["event"] config_func <- function(x) x@funs["config"] info_func <- function(x) x@funs["info"] #nocov end @@ -42,7 +43,7 @@ clean_symbol <- function(x) { gsub("[[:punct:]]", "__", x) } -funs_create <- function(model, what = c("main", "ode", "table", "config")) { +funs_create <- function(model, what = c("main", "ode", "table", "event", "config")) { setNames(paste0("_model_", clean_symbol(model), "_", what ,"__"),what) } @@ -55,7 +56,7 @@ package_loaded <- function(x) { } funs <- function(x) { - x@funs[c("main", "ode", "table", "config")] + x@funs[c("main", "ode", "table", "event", "config")] } model_loaded <- function(x) { diff --git a/R/handle_spec_block.R b/R/handle_spec_block.R index bfd09821..258a1402 100644 --- a/R/handle_spec_block.R +++ b/R/handle_spec_block.R @@ -566,6 +566,17 @@ handle_spec_block.specTABLE <- function(x, env, ...) { return(x) } +#' @export +handle_spec_block.specEVENT <- function(x, env, ...) { + + x <- dump_opts(x) + + pos <- attr(x,"pos") + + check_block_data(x, env, pos) + + return(x) +} # NMXML -------------------------------- #' @export diff --git a/R/modlib.R b/R/modlib.R index ed82ac5e..80025fbc 100644 --- a/R/modlib.R +++ b/R/modlib.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2021 Metrum Research Group +# Copyright (C) 2013 - 2024 Metrum Research Group # # This file is part of mrgsolve. # @@ -55,8 +55,9 @@ ##' mod <- mread("viral2", modlib()) ##' mod <- mread("pred1", modlib()) ##' mod <- mread("pbpk", modlib()) -##' mod <- mread("1005", modlib()) # embedded NONMEM result +##' mod <- mread("1005", modlib()) # embedded NONMEM result ##' mod <- mread("nm-like", modlib()) # model with nonmem-like syntax +##' mod <- mread("evtools", modlib()) ##' ##' mrgsolve:::code(mod) ##' } @@ -75,7 +76,7 @@ modlib <- function(model = NULL,...,list=FALSE) { modlib_models <- c( "pk1cmt", "pk2cmt", "pk3cmt", "pk", "pk1", "pk2", "popex", "irm1", "irm2", "irm3", "pred1", "emax", "tmdd", "viral1", - "viral2", "effect", "1005", "nm-like" + "viral2", "effect", "1005", "nm-like", "evtools" ) #nocov end diff --git a/R/modspec.R b/R/modspec.R index fcdfb56d..2f8ce692 100644 --- a/R/modspec.R +++ b/R/modspec.R @@ -368,7 +368,7 @@ param_re_find <- "\\bparam\\s+\\w+\\s*=" # please-deprecate move_global <- function(x,env) { - what <- intersect(c("PREAMBLE","MAIN", "ODE", "TABLE", "PRED"),names(x)) + what <- intersect(c("PREAMBLE","MAIN", "ODE", "TABLE", "EVENT", "PRED"),names(x)) if(length(what)==0) return(x) @@ -495,12 +495,17 @@ move_global2 <- function(spec, env, build) { if(!is.null(table$code)) { spec$TABLE <- table$code } + event <- c_vars(spec[["EVENT"]], context = "event") + if(!is.null(event$code)) { + spec$EVENT <- event$code + } to_ns <- bind_rows( pream$vars, pred$vars, main$vars, ode$vars, - table$vars + table$vars, + event$vars ) vars <- bind_rows(glob$vars, to_ns) if(any(cap <- to_ns$type=="capture")) { @@ -536,7 +541,7 @@ move_global2 <- function(spec, env, build) { } find_cpp_dot <- function(spec, env) { - to_check <- c("PREAMBLE", "MAIN", "PRED", "ODE", "TABLE", "GLOBAL") + to_check <- c("PREAMBLE", "MAIN", "PRED", "ODE", "EVENT", "TABLE", "GLOBAL") x <- spec[names(spec) %in% to_check] x <- unlist(x, use.names = FALSE) # Narrow the search first; 10x speed up when searching for `pattern` diff --git a/R/mread.R b/R/mread.R index ac072ac4..e340fdbe 100644 --- a/R/mread.R +++ b/R/mread.R @@ -336,10 +336,11 @@ mread <- function(model, project = getOption("mrgsolve.project", getwd()), rd <- generate_rdefs( pars = Pars(x), cmt = Cmt(x), - ode_func(x), - main_func(x), - table_func(x), - config_func(x), + func = ode_func(x), + init_fun = main_func(x), + table_fun = table_func(x), + event_fun = event_func(x), + config_fun = config_func(x), model = model(x), omats = omat(x), smats = smat(x), @@ -375,7 +376,7 @@ mread <- function(model, project = getOption("mrgsolve.project", getwd()), } # autodec if("autodec" %in% names(plugin)) { - auto_blocks <- c("PREAMBLE", "MAIN", "PRED", "ODE", "TABLE") + auto_blocks <- c("PREAMBLE", "MAIN", "PRED", "ODE", "TABLE", "EVENT") auto_skip <- cvec_cs(ENV[["MRGSOLVE_AUTODEC_SKIP"]]) autov <- autodec_vars(spec, blocks = auto_blocks) autov <- autodec_clean( @@ -461,6 +462,7 @@ mread <- function(model, project = getOption("mrgsolve.project", getwd()), x@shlib[["nm_import"]] <- mread.env[["nm_import"]] x@shlib[["source"]] <- file.path(build[["soloc"]],build[["compfile"]]) x@shlib[["md5"]] <- build[["md5"]] + x@shlib[["call_event"]] <- "EVENT" %in% names(spec) # build---- # In soloc directory @@ -536,6 +538,10 @@ mread <- function(model, project = getOption("mrgsolve.project", getwd()), dbs[["ode"]], spec[["ODE"]], "__END_ode__", + "\n// MODELED EVENTS:", + "__BEGIN_event__", + spec[["EVENT"]], + "__END_event__", "\n// TABLE CODE BLOCK:", "__BEGIN_table__", dbs[["cmt"]], diff --git a/R/nm-mode.R b/R/nm-mode.R index 82884a19..f61d58a5 100644 --- a/R/nm-mode.R +++ b/R/nm-mode.R @@ -22,7 +22,7 @@ find_nm_vars <- function(spec) { ans[["has_ode"]] <- "ODE" %in% names(spec) FRDA <- c("F", "R", "D", "ALAG") # CHeck non-ODE - blocks_to_check <- c("PREAMBLE", "MAIN", "TABLE") + blocks_to_check <- c("PREAMBLE", "MAIN", "TABLE", "EVENT") pmt <- unlist(spec[blocks_to_check], use.names = FALSE) m1 <- find_nm_vars_impl(pmt) # Check ODE diff --git a/inst/base/modelheader.h b/inst/base/modelheader.h index fc8694fe..5a781a8e 100644 --- a/inst/base/modelheader.h +++ b/inst/base/modelheader.h @@ -65,6 +65,8 @@ typedef double capture; #define __END_main__ __DONE__ #define __BEGIN_table__ extern "C" { void __TABLECODE___(MRGSOLVE_TABLE_SIGNATURE) { #define __END_table__ __DONE__ +#define __BEGIN_event__ extern "C" {void __EVENTFUN___(MRGSOLVE_EVENT_SIGNATURE) { +#define __END_event__ __DONE__ #define __DONE__ }} diff --git a/inst/base/mrgsolv.h b/inst/base/mrgsolv.h index 58ab5219..2be79ada 100644 --- a/inst/base/mrgsolv.h +++ b/inst/base/mrgsolv.h @@ -132,6 +132,10 @@ typedef std::vector dvec; #define MRGSOLVE_TABLE_SIGNATURE const dvec& _A_, const dvec& _A_0_, dvec& _THETA_, const dvec& _F_, const dvec& _R_, databox& self, const dvec& _pred_, dvec& _capture_, mrgsolve::resim& simeps #define MRGSOLVE_TABLE_SIGNATURE_N 9 +//! signature for $EVENT same as what we use for $TABLE +#define MRGSOLVE_EVENT_SIGNATURE MRGSOLVE_TABLE_SIGNATURE +#define MRGSOLVE_EVENT_SIGNATURE_N MRGSOLVE_TABLE_SIGNATURE_N + //! signature for $ODE #define MRGSOLVE_ODE_SIGNATURE const double* _ODETIME_, const double* _A_, double* _DADT_, const dvec& _A_0_, const dvec& _THETA_, const bool _ss_flag_ #define MRGSOLVE_ODE_SIGNATURE_N 6 diff --git a/inst/include/odeproblem.h b/inst/include/odeproblem.h index 76b51f0e..7e7a536e 100644 --- a/inst/include/odeproblem.h +++ b/inst/include/odeproblem.h @@ -48,6 +48,9 @@ typedef void (*init_func)(MRGSOLVE_INIT_SIGNATURE); //! $TABLE function typedef void (*table_func)(MRGSOLVE_TABLE_SIGNATURE); +//! $EVENT function +typedef void (*event_func)(MRGSOLVE_EVENT_SIGNATURE); + //! $ODE function typedef void (*deriv_func)(MRGSOLVE_ODE_SIGNATURE); @@ -115,6 +118,7 @@ class odeproblem { void table_call(); void table_init_call(); + void event_call(); void config_call(); void set_d(rec_ptr this_rec); @@ -249,6 +253,7 @@ class odeproblem { deriv_func Derivs; ///< $ODE function init_func Inits; ///< $MAIN function table_func Table; ///< $TABLE function + event_func Event; ///< $EVENT function config_func Config; ///< $PREAMBLE function bool Do_Init_Calc; ///< Flag regulating whether or not initials are taken from $MAIN diff --git a/inst/maintenance/unit-cpp/test-event-block.R b/inst/maintenance/unit-cpp/test-event-block.R new file mode 100644 index 00000000..46c58045 --- /dev/null +++ b/inst/maintenance/unit-cpp/test-event-block.R @@ -0,0 +1,129 @@ +library(testthat) +library(mrgsolve) +library(dplyr) + +Sys.setenv(R_TESTS="") + +options("mrgsolve_mread_quiet"=TRUE) + +local_edition(3) + +code_event <- ' +$PLUGIN evtools nm-vars autodec + +$PARAM +Ii = 24 +Ss = 1 +Addl = 3 +Amt = 100 +Rate = 20 +CL = 2 +V = 20 + +$PKMODEL cmt = "B" + +$EVENT +if(TIME==0) { + evt::ev dose = evt::infuse(Amt, 1, Rate); + evt::ss(dose, Ss); + evt::ii(dose, Ii); + evt::addl(dose, Addl); + self.push(dose); +} +capture b = A(1)/V; +capture c = 1.23; +double d = 50; + +$ERROR +capture cp = B/V; +e = d/2; + +$CAPTURE e d +' + +code_error <- ' +$PLUGIN evtools nm-vars autodec + +$PARAM +Ii = 24 +Ss = 1 +Addl = 3 +Amt = 100 +Rate = 20 +CL = 2 +V = 20 + +$PKMODEL cmt = "B" + +$ERROR +if(TIME==0) { + evt::ev dose = evt::infuse(Amt, 1, Rate); + evt::ss(dose, Ss); + evt::ii(dose, Ii); + evt::addl(dose, Addl); + self.push(dose); +} +capture cp = B/V; +' + +mod1 <- mcode("test-event", code_event, delta = 0.1, end = 120) +mod2 <- mcode("test-error", code_error, delta = 0.1, end = 120) + +outev <- mrgsim(mod1) +outer <- mrgsim(mod2) + +test_that("$EVENT result matches $TABLE results", { + expect_identical(outev$B, outer$B) + # Known that cp isn't calculated when $TABLE is used + expect_equal(outer$cp[1], 0) + # Using $EVENT allows this to be calculated + expect_equal(outev$cp[1], outev$B[1]/mod1$V) + i <- seq(nrow(outer))[-1] + expect_equal(outer$cp[i], outev$cp[i]) +}) + +test_that("declare inside $EVENT", { + expect_true(all(outev$d == 50)) + expect_true(all(outev$e == outev$d/2)) +}) + +test_that("capture from $EVENT", { + expect_true(all(abs(outev$c - 1.23) < 1e-7)) + expect_equal(outev$b, outer$cp) +}) + +test_that("check internals", { + f <- mrgsolve:::funset(mod1) + expect_equal(nrow(f$symbols), 5) + expect_true(all(f$symbols$loaded)) + expect_equal(f$symbols$name[4], "_model_test__event_event__") + + p <- mrgsolve:::pointers(mod1) + expect_equal(length(p), 5) + expect_equal(names(p)[4], "event") + + expect_true(mod1@shlib$call_event) + expect_false(mod2@shlib$call_event) + + df <- as.list(mod1)$cpp_variables + cap <- df[df$type=="capture",] + expect_equal(cap$var, c("cp", "b", "c")) + expect_equal(cap$context, c("table", "event", "event")) + + auto <- df[df$context=="auto", ] + expect_true(all(auto$type=="double")) + expect_equal(auto$var[1], "e") + + f <- mrgsolve:::funset(house()) + expect_equal(nrow(f$symbols), 5) + expect_true(all(f$symbols$loaded)) + expect_equal(f$symbols$name[4], "_model_housemodel_event__") + + p <- mrgsolve:::pointers(house()) + expect_equal(length(p), 5) + expect_equal(names(p)[4], "event") + + expect_false(house()@shlib$call_event) +}) + + diff --git a/inst/maintenance/unit/test-modlib.R b/inst/maintenance/unit/test-modlib.R index dea3860d..7ba71684 100644 --- a/inst/maintenance/unit/test-modlib.R +++ b/inst/maintenance/unit/test-modlib.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2020 Metrum Research Group +# Copyright (C) 2013 - 2024 Metrum Research Group # # This file is part of mrgsolve. # @@ -100,9 +100,21 @@ test_that("all modlib models", { expect_is(x[[1]],"mrgmod") expect_is(x[[2]],"mrgsims") + x <- test_lib("pbpk") + expect_is(x[[1]],"mrgmod") + expect_is(x[[2]],"mrgsims") + + x <- test_lib("1005") + expect_is(x[[1]],"mrgmod") + expect_is(x[[2]],"mrgsims") + x <- test_lib("nm-like") expect_is(x[[1]],"mrgmod") expect_is(x[[2]],"mrgsims") + + x <- test_lib("evtools") + expect_is(x[[1]],"mrgmod") + expect_is(x[[2]],"mrgsims") }) diff --git a/inst/models/evtools.cpp b/inst/models/evtools.cpp new file mode 100644 index 00000000..a11329b1 --- /dev/null +++ b/inst/models/evtools.cpp @@ -0,0 +1,68 @@ +$PROB +# Example model using evtools plugin + +- Regimen 1 is a single infusion dose to DEPOT +- Regimen 2 is steady state bolus dosing +- Regimen 3 is a dosing regimen using `regimen` object + +$PLUGIN evtools + +$GLOBAL +evt::regimen reg; + +$SET end = 264, delta = 0.5 + +$PARAM +TVKA = 1.2, TVCL = 1, TVV = 20 +Amt = 100, Dur = 0, Ii = 24, Addl = 9, Ss = 1 +REG = 1, Until = 24*8 + +$INPUT WT = 70 + +$PKMODEL cmt = "DEPOT CENT", depot = TRUE + +$PREAMBLE +reg.init(self); + +$PK +if(NEWIND < 1) reg.init(self); + +double CL = exp(log(TVCL) + 0.75*log(WT/70) + ETA(1)); +double V = exp(log(TVV) + log(WT/70) + ETA(2)); +double KA = exp(log(TVKA) + ETA(3)); + +double Rate = Dur > 0 ? Amt / Dur : 0; + +$OMEGA 0.09 0.1 0.01 + +$SIGMA 0 + +$EVENT +if(TIME != 0) return; + +if(REG==1) { + evt::infuse(self, Amt, 2, Rate); +} + +if(REG==2) { + evt::ev dose = evt::bolus(Amt, 1); + evt::ii(dose, Ii); + evt::addl(dose, Addl); + evt::ss(dose, Ss); + self.push(dose); +} + +if(REG==3) { + reg.init(self); + reg.amt(Amt); + reg.cmt(1); + reg.rate(Rate); + reg.ii(Ii); + reg.until(Until); +} + +$TABLE +capture IPRED = CENT/V; +capture DV = IPRED*exp(EPS(1)); + +if(REG==3) reg.execute(); diff --git a/man/modlib.Rd b/man/modlib.Rd index 5f116758..0768018f 100644 --- a/man/modlib.Rd +++ b/man/modlib.Rd @@ -47,8 +47,9 @@ mod <- mread("viral1", modlib()) mod <- mread("viral2", modlib()) mod <- mread("pred1", modlib()) mod <- mread("pbpk", modlib()) -mod <- mread("1005", modlib()) # embedded NONMEM result +mod <- mread("1005", modlib()) # embedded NONMEM result mod <- mread("nm-like", modlib()) # model with nonmem-like syntax +mod <- mread("evtools", modlib()) mrgsolve:::code(mod) } diff --git a/src/devtran.cpp b/src/devtran.cpp index bac83507..e8dd3f82 100644 --- a/src/devtran.cpp +++ b/src/devtran.cpp @@ -61,6 +61,7 @@ Rcpp::List DEVTRAN(const Rcpp::List parin, const bool tad = Rcpp::as (parin["tad"]); const bool nocb = Rcpp::as (parin["nocb"]); bool obsaug = Rcpp::as (parin["obsaug"] ); + bool call_event = Rcpp::as (parin["call_event"]); obsaug = obsaug & (data.nrow() > 0); // Grab items from the model object -------------------- @@ -616,9 +617,12 @@ Rcpp::List DEVTRAN(const Rcpp::List parin, } if(!this_rec->is_lagged()) { - prob.table_call(); + if(call_event) { + prob.event_call(); + } else { + prob.table_call(); + } } - if(prob.any_mtime()) { // Will set used_mtimehx only if we push back std::vector mt = prob.mtimes(); @@ -716,7 +720,11 @@ Rcpp::List DEVTRAN(const Rcpp::List parin, used_mtimehx = mtimehx.size() > 0; prob.clear_mtime(); } // Close handling of modeled events - + + if(call_event && !this_rec->is_lagged()) { + prob.table_call(); + } + if(this_rec->output()) { ans(crow,0) = id; ans(crow,1) = tto; diff --git a/src/housemodel-mread-header.h b/src/housemodel-mread-header.h index 5845b2ec..672c9812 100644 --- a/src/housemodel-mread-header.h +++ b/src/housemodel-mread-header.h @@ -41,6 +41,7 @@ typedef double localdouble; #define __INITFUN___ _model_housemodel_main__ #define __ODEFUN___ _model_housemodel_ode__ #define __TABLECODE___ _model_housemodel_table__ +#define __EVENTFUN___ _model_housemodel_event__ #define __CONFIGFUN___ _model_housemodel_config__ #define __REGISTERFUN___ R_init_housemodel #define _nEQ 3 diff --git a/src/housemodel-mread-source.cpp b/src/housemodel-mread-source.cpp index f7e5a130..21030372 100644 --- a/src/housemodel-mread-source.cpp +++ b/src/housemodel-mread-source.cpp @@ -24,6 +24,10 @@ dxdt_CENT = KAi*GUT - (CLi/VCi)*CENT; dxdt_RESP = KIN*(1-INH) - KOUTi*RESP; __END_ode__ +// MODELED EVENTS: +__BEGIN_event__ +__END_event__ + // TABLE CODE BLOCK: __BEGIN_table__ DV = CP*exp(EXPO); diff --git a/src/mrgsolve.cpp b/src/mrgsolve.cpp index 382c5e9a..4f43a2a5 100644 --- a/src/mrgsolve.cpp +++ b/src/mrgsolve.cpp @@ -453,5 +453,3 @@ Rcpp::List mat2df(Rcpp::NumericMatrix const& x) { } #endif - - diff --git a/src/mrgsolve_init.cpp b/src/mrgsolve_init.cpp index 67249280..88caa09a 100644 --- a/src/mrgsolve_init.cpp +++ b/src/mrgsolve_init.cpp @@ -61,6 +61,7 @@ RcppExport void _model_housemodel_main__(MRGSOLVE_INIT_SIGNATURE); RcppExport void _model_housemodel_ode__(MRGSOLVE_ODE_SIGNATURE); RcppExport void _model_housemodel_table__(MRGSOLVE_TABLE_SIGNATURE); RcppExport void _model_housemodel_config__(MRGSOLVE_CONFIG_SIGNATURE); +RcppExport void _model_housemodel_event__(MRGSOLVE_EVENT_SIGNATURE); static R_CallMethodDef callEntryPoints[] = { CALLDEF(_mrgsolve_get_tokens,1), @@ -75,6 +76,7 @@ static R_CallMethodDef callEntryPoints[] = { CALLDEF(_model_housemodel_main__,MRGSOLVE_INIT_SIGNATURE_N), CALLDEF(_model_housemodel_ode__,MRGSOLVE_ODE_SIGNATURE_N), CALLDEF(_model_housemodel_table__,MRGSOLVE_TABLE_SIGNATURE_N), + CALLDEF(_model_housemodel_event__,MRGSOLVE_EVENT_SIGNATURE_N), CALLDEF(_model_housemodel_config__,MRGSOLVE_CONFIG_SIGNATURE_N), {NULL, NULL, 0} }; diff --git a/src/odeproblem.cpp b/src/odeproblem.cpp index a50a6bc1..5a3047a3 100644 --- a/src/odeproblem.cpp +++ b/src/odeproblem.cpp @@ -113,9 +113,10 @@ odeproblem::odeproblem(Rcpp::List param, *reinterpret_cast(&Inits) = R_ExternalPtrAddr(funs["main"]); *reinterpret_cast(&Table) = R_ExternalPtrAddr(funs["table"]); + *reinterpret_cast(&Event) = R_ExternalPtrAddr(funs["event"]); *reinterpret_cast(&Derivs) = R_ExternalPtrAddr(funs["ode"]); *reinterpret_cast(&Config) = R_ExternalPtrAddr(funs["config"]); - + Capture.assign(n_capture_,0.0); simeta = mrgsolve::resim(&dosimeta,reinterpret_cast(this)); @@ -244,6 +245,11 @@ void odeproblem::table_call() { Table(Y,Init_value,Param,F,R,d,pred,Capture,simeps); } +//! Call $EVENT function. +void odeproblem::event_call() { + Event(Y,Init_value,Param,F,R,d,pred,Capture,simeps); +} + //! Call $PREAMBLE function. void odeproblem::config_call() { Config(d,Param,Neq,Npar); @@ -684,6 +690,7 @@ void odeproblem::copy_parin(const Rcpp::List& parin, const Rcpp::S4& mod) { void odeproblem::copy_funs(const Rcpp::List& funs) { *reinterpret_cast(&Inits) = R_ExternalPtrAddr(funs["main"]); *reinterpret_cast(&Table) = R_ExternalPtrAddr(funs["table"]); + *reinterpret_cast(&Event) = R_ExternalPtrAddr(funs["event"]); *reinterpret_cast(&Derivs) = R_ExternalPtrAddr(funs["ode"]); *reinterpret_cast(&Config) = R_ExternalPtrAddr(funs["config"]); }