Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add $EVENT block #1230

Merged
merged 28 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
30ed899
model pointers are now stored in the model object
kylebaron Sep 8, 2024
e6968f4
add pointers getter
kylebaron Sep 8, 2024
50eabb3
add
kylebaron Sep 8, 2024
8e83538
tweak implementation
kylebaron Sep 8, 2024
ba67c9e
move call to after events are processed
kylebaron Sep 9, 2024
665def8
different calling sequence when EVENT is in the mix
kylebaron Sep 10, 2024
6ea4d71
tweak logic
kylebaron Sep 10, 2024
ce6bc9c
add handler for EVENT blocks
kylebaron Sep 10, 2024
017b67a
more changes for EVENT block
kylebaron Sep 10, 2024
b8de0f2
drop pointer cache; will re-do later
kylebaron Sep 10, 2024
7a29e1a
revert changes in funset
kylebaron Sep 10, 2024
59935fb
revert more funset
kylebaron Sep 10, 2024
f900793
revert more
kylebaron Sep 10, 2024
aae568a
revert
kylebaron Sep 10, 2024
efbbf4e
spaces
kylebaron Sep 10, 2024
e78c79c
revert
kylebaron Sep 10, 2024
da42b01
don't save x back
kylebaron Sep 10, 2024
99160c9
tests for event blocjk
kylebaron Sep 12, 2024
78da749
more tests on event block
kylebaron Sep 12, 2024
e49ddd7
fix comment
kylebaron Sep 12, 2024
3614e1e
tests for event-block
kylebaron Sep 13, 2024
4dc7cad
fix tests
kylebaron Sep 13, 2024
9eeed73
don't pass by position; make defaults consistent
kylebaron Sep 14, 2024
9f4637d
bump version for testing
kylebaron Sep 14, 2024
5dc2327
move EVENT
kylebaron Sep 14, 2024
1d02ff2
revert compiled check
kylebaron Sep 24, 2024
78341f5
update file header
kylebaron Sep 24, 2024
3f41e40
event and table have the same signature
kylebaron Sep 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion R/Aaaa.R
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ GLOBALS$TRAN_FILL_NA <- c(
)
GLOBALS[["version"]] <- utils::packageVersion("mrgsolve")

block_list <- c("ENV", "PROB", "PARAM", "INIT",
block_list <- c("ENV", "PROB", "PARAM", "INIT", "EVENT",
"CMT", "ODE", "DES", "MAIN", "TABLE",
"FIXED", "CMTN", "THETA", "NMXML", "VCMT",
"PKMODEL", "PLUGIN", "INCLUDE", "NAMESPACE",
Expand Down
4 changes: 4 additions & 0 deletions R/RcppExports.R
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ EXPAND_OBSERVATIONS <- function(data, times, to_copy, next_pos) {
.Call(`_mrgsolve_EXPAND_OBSERVATIONS`, data, times, to_copy, next_pos)
}

VALIDPOINTERS <- function(x) {
.Call(`_mrgsolve_VALIDPOINTERS`, x)
}

TOUCH_FUNS <- function(funs, mod) {
.Call(`_mrgsolve_TOUCH_FUNS`, funs, mod)
}
Expand Down
9 changes: 6 additions & 3 deletions R/class_mrgmod.R
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
# along with mrgsolve. If not, see <http://www.gnu.org/licenses/>.

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.",
Expand Down Expand Up @@ -348,6 +348,7 @@ house <- function(...) {
)
x@soloc <- dirname(sodll(x))
x <- compiled(x,TRUE)
x <- setpointers(x)
x <- update(x,...,open=TRUE)
x
}
Expand Down Expand Up @@ -701,6 +702,7 @@ loadso.mrgmod <- function(x,...) {
if(inherits(foo, "try-error")) {
wstop("[loadso] failed to load the model dll file")
}
x <- setpointers(x)
return(invisible(x))
}

Expand Down Expand Up @@ -794,7 +796,8 @@ parin <- function(x) {
ss_n = 500,
ss_fixed = FALSE,
interrupt = -1,
etasrc = "omega"
etasrc = "omega",
call_event = x@shlib$call_event
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've saved a logical value indicating of $EVENT is in the model; if so, tell whether or not to call.

)
}

Expand Down
2 changes: 2 additions & 0 deletions R/compile.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ generate_rdefs <- function(pars,
func,
init_fun="",
table_fun="",
event_fun="",
config_fun="",
model="",omats,smats,
set=list(),
Expand Down Expand Up @@ -91,6 +92,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),
Expand Down
38 changes: 26 additions & 12 deletions R/funset.R
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
}

Expand All @@ -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) {
Expand All @@ -67,47 +68,60 @@ which_loaded <- function(x) {
}

funs_loaded <- function(x,crump=TRUE) {
main_loaded(x) && compiled.mrgmod(x)
main_loaded(x) && x@shlib$compiled
}

all_loaded <- function(x) all(which_loaded(x))

pointers <- function(x) {
pointers <- function(x, refresh = FALSE) {
if(!funs_loaded(x)) {
try_load <- try(loadso(x), silent = TRUE)
if(inherits(try_load, "try-error") || !funs_loaded(x)) {
message(try_load)
stop(FUNSET_ERROR__)
}
}
if(!refresh && VALIDPOINTERS(getpointers(x))) {
return(getpointers(x))
}
what <- funs(x)
ans <- getNativeSymbolInfo(what,PACKAGE=dllname(x))
setNames(lapply(ans, "[[", "address"), names(what))
}

setpointers <- function(x) {
x@shlib$pointers <- pointers(x, refresh = TRUE)
x
}

getpointers <- function(x) {
x@shlib$pointers
}

funset <- function(x) {
pkg <- dllname(x)
ans <- lapply(unname(funs(x)), function(w) {
loaded <- is.loaded(w,pkg)
if(loaded) {
info <- getNativeSymbolInfo(w,pkg)
name <- info$name
addr <- deparse(info$address)
} else {
name <- w
addr <- "."
}
tibble(name=name,loaded=loaded)
tibble(name=name,address=addr,loaded=loaded)
})

ans <-
bind_rows(unname(ans)) %>%
mutate(func = names(funs(x)))
ans <- bind_rows(unname(ans))
ans <- mutate(ans, func = names(funs(x)))

ans <- as.data.frame(ans[,c("name", "loaded"),drop=FALSE])
ans <- as.data.frame(ans[,c("func", "name", "address", "loaded"),drop=FALSE])

shlib <- tibble(
package=pkg,
version=as.character(build_version(x)),
compiled=compiled(x)
package = pkg,
version = as.character(build_version(x)),
compiled = compiled(x)
)

list(symbols = ans, shlib = data.frame(shlib))
Expand Down
11 changes: 8 additions & 3 deletions R/modspec.R
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated this, but it's not in use any more (see comment). I'd rather get rid of it at this point, but it may or may not be in scope of this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking a quick look at move_global, I think a dedicated/separate PR would be better.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree.


if(length(what)==0) return(x)

Expand Down Expand Up @@ -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
)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is happening in the new version (move_global2()).

vars <- bind_rows(glob$vars, to_ns)
if(any(cap <- to_ns$type=="capture")) {
Expand Down Expand Up @@ -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`
Expand Down
10 changes: 9 additions & 1 deletion R/mread.R
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ mread <- function(model, project = getOption("mrgsolve.project", getwd()),
ode_func(x),
main_func(x),
table_func(x),
event_func(x),
config_func(x),
model = model(x),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added argument names for safety ... was getting called by position before.

omats = omat(x),
Expand Down Expand Up @@ -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)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will pass this into the C+ simulation code to tell if we are using $EVENT to create modeled doses.


# build----
# In soloc directory
Expand Down Expand Up @@ -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"]],
Expand Down Expand Up @@ -595,6 +601,8 @@ mread <- function(model, project = getOption("mrgsolve.project", getwd()),

x <- compiled(x,TRUE)

x <- setpointers(x)

return(x)
}

Expand Down Expand Up @@ -636,7 +644,7 @@ mread_cache <- function(model = NULL,

if(all(t0,t1,t2,t3,t4,te)) {
if(!quiet) message("Loading model from cache.")
loadso(x)
x <- loadso(x)
return(update(x,...,strict=FALSE))
}

Expand Down
2 changes: 2 additions & 0 deletions inst/base/modelheader.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ }}


Expand Down
4 changes: 4 additions & 0 deletions inst/base/mrgsolv.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,8 @@ typedef std::vector<double> dvec;
#define MRGSOLVE_CONFIG_SIGNATURE databox& self, const dvec& _THETA_, const double neq, const double npar
#define MRGSOLVE_CONFIG_SIGNATURE_N 4

//! signature for <code>$EVENT</code>
#define MRGSOLVE_EVENT_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_EVENT_SIGNATURE_N 9

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is important; I'm having $EVENT function identical to $TABLE. Anything you could do in one, you could do in the other.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could re-use that signature macro to emphasize this (e.g. use MRGSOLVE_TABLE_SIGNATURE for the event; what do you think? maybe it would be confusing or look like a mistake or it could ensure they act the same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could ensure they act the same.

I like the idea of sharing for this reason, and I think the confusion could be made less likely by the combination of 1) putting in a code comment and 2) moving the macros next to each other.

Another idea: what about renaming MRGSOLVE_TABLE_SIGNATURE/MRGSOLVE_TABLE_SIGNATURE_N to indicate both TABLE and EVENT and then using it for both? I suppose MRGSOLVE_TABLE_OR_EVENT_SIGNATURE is getting a bit long, but I think it'd resolve both points above.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I moved the macros next to each other and noted they are the same. I ended up copying the TABLE macro into the EVENT macro. So they will have different names in the code, but guaranteed to be in sync.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to send this off to winbuilder just to make sure the macros are behaving as I think they will on gcc. If that comes back ok, will merge.

#endif
5 changes: 5 additions & 0 deletions inst/include/odeproblem.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ typedef void (*init_func)(MRGSOLVE_INIT_SIGNATURE);
//! <code>$TABLE</code> function
typedef void (*table_func)(MRGSOLVE_TABLE_SIGNATURE);

//! <code>$EVENT</code> function
typedef void (*event_func)(MRGSOLVE_EVENT_SIGNATURE);

//! <code>$ODE</code> function
typedef void (*deriv_func)(MRGSOLVE_ODE_SIGNATURE);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -249,6 +253,7 @@ class odeproblem {
deriv_func Derivs; ///< <code>$ODE</code> function
init_func Inits; ///< <code>$MAIN</code> function
table_func Table; ///< <code>$TABLE</code> function
event_func Event; ///< <code>$EVENT</code> function
config_func Config; ///< <code>$PREAMBLE</code> function

bool Do_Init_Calc; ///< Flag regulating whether or not initials are taken from <code>$MAIN</code>
Expand Down
11 changes: 11 additions & 0 deletions src/RcppExports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,17 @@ BEGIN_RCPP
return rcpp_result_gen;
END_RCPP
}
// VALIDPOINTERS
bool VALIDPOINTERS(Rcpp::List x);
RcppExport SEXP _mrgsolve_VALIDPOINTERS(SEXP xSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< Rcpp::List >::type x(xSEXP);
rcpp_result_gen = Rcpp::wrap(VALIDPOINTERS(x));
return rcpp_result_gen;
END_RCPP
}
// TOUCH_FUNS
Rcpp::List TOUCH_FUNS(const Rcpp::List& funs, const Rcpp::S4 mod);
RcppExport SEXP _mrgsolve_TOUCH_FUNS(SEXP funsSEXP, SEXP modSEXP) {
Expand Down
15 changes: 12 additions & 3 deletions src/devtran.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Rcpp::List DEVTRAN(const Rcpp::List parin,
const bool tad = Rcpp::as<bool> (parin["tad"]);
const bool nocb = Rcpp::as<bool> (parin["nocb"]);
bool obsaug = Rcpp::as<bool> (parin["obsaug"] );
bool call_event = Rcpp::as<bool> (parin["call_event"]);
obsaug = obsaug & (data.nrow() > 0);

// Grab items from the model object --------------------
Expand Down Expand Up @@ -615,8 +616,12 @@ Rcpp::List DEVTRAN(const Rcpp::List parin,
}
}

if(!this_rec->is_lagged()) {
prob.table_call();
if(call_event) {
prob.event_call();
} else {
if(!this_rec->is_lagged()) {
prob.table_call();
}
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the first work around to maintain event code in $EVENT and $TABLE. Basically, if the user has $EVENT block, then call that one here; otherwise call $TABLE. Down below, we'll call $TABLE if $EVENT was called and do nothing if it wasn't.


if(prob.any_mtime()) {
Expand Down Expand Up @@ -716,7 +721,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()) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second bit of "workaround" code to maintain event creation in both $EVENT and $TABLE.

ans(crow,0) = id;
ans(crow,1) = tto;
Expand Down
1 change: 1 addition & 0 deletions src/housemodel-mread-header.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions src/housemodel-mread-source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was programmatically generaged; every model will have this in the source going fowward.

__BEGIN_table__
DV = CP*exp(EXPO);
Expand Down
11 changes: 10 additions & 1 deletion src/mrgsolve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,4 +454,13 @@ Rcpp::List mat2df(Rcpp::NumericMatrix const& x) {

#endif


// [[Rcpp::export]]
bool VALIDPOINTERS(Rcpp::List x) {
if(x.size()==0) return false;
for(size_t i = 0; i < x.size(); ++i) {
if(R_ExternalPtrAddr(x[i]) == NULL) {
return false;
}
}
return true;
}
Loading
Loading