diff --git a/R/rxValidate.R b/R/rxValidate.R index 84ed0b9b6..3743e303b 100644 --- a/R/rxValidate.R +++ b/R/rxValidate.R @@ -1,3 +1,4 @@ + #' Validate rxode2 #' This allows easy validation/qualification of nlmixr by running the #' testing suite on your system. @@ -53,5 +54,3 @@ rxValidate <- function(type = NULL, skipOnCran=TRUE) { #' @rdname rxValidate #' @export rxTest <- rxValidate - - diff --git a/vignettes/articles/Integrating-User-Defined-Functions-into-rxode2.Rmd b/vignettes/articles/Integrating-User-Defined-Functions-into-rxode2.Rmd index a4497595e..a3273a187 100644 --- a/vignettes/articles/Integrating-User-Defined-Functions-into-rxode2.Rmd +++ b/vignettes/articles/Integrating-User-Defined-Functions-into-rxode2.Rmd @@ -23,7 +23,12 @@ When defining models you may have wished to write a small R function or make a f ## R based user functions -A R-based user function is the most convenient to include in the ODE, but is slower than what you could have done if it was written in `C` , `C++` or some other compiled language. This was requested [in github](https://github.com/nlmixrdevelopment/RxODE/issues/162#issue-568886732) with an appropriate example; However, I will use a very simple example here to simply illustrate the concepts. +A R-based user function is the most convenient to include in the ODE, +but is slower than what you could have done if it was written in `C` , +`C++` or some other compiled language. This was requested [in +github](https://github.com/nlmixrdevelopment/RxODE/issues/162#issue-568886732) +with an appropriate example; However, I will use a very simple example +here to simply illustrate the concepts. ```{r fExample} newAbs <- function(x) { @@ -33,6 +38,7 @@ newAbs <- function(x) { x } } + f <- rxode2({ a <- newAbs(time) }) @@ -40,7 +46,11 @@ f <- rxode2({ e <- et(-10, 10, length.out=40) ``` -Now that the ODE has been compiled the R functions will be called while solving the ODE. Since this is calling R, this forces the parallization to be turned off since R is single-threaded. It also takes more time to solve since it is shuttling back and forth between R and C. Lets see how this very simple function performs: +Now that the ODE has been compiled the R functions will be called +while solving the ODE. Since this is calling R, this forces the +parallization to be turned off since R is single-threaded. It also +takes more time to solve since it is shuttling back and forth between +R and C. Lets see how this very simple function performs: ```{r benmchmark1} mb1 <- microbenchmark::microbenchmark(withoutC=suppressWarnings(rxSolve(f,e))) @@ -58,7 +68,7 @@ You can make it a better by converting the functions to C: rxFun(newAbs) # Recompile to use the C functions # Note it would recompile anyway if you didn't do this step, -# it just makes sure that it doesn't recompile every step in +# it just makes sure that it doesn't recompile every step in # the benchmark f <- rxode2({ a <- newAbs(time) @@ -71,7 +81,12 @@ autoplot(mb) + rxTheme() + xgxr::xgx_scale_y_log10() print(mb) ``` -The C version is almost twice as fast as the R version. You may have noticed the conversion also created C versions of the first derivative. This is done automatically and gives not just C versions of function, but C versions of the derivatives and registers them with `rxode2`. This allows the C versions to work with not only `rxode2` but `nlmixr2` models. +The C version is almost twice as fast as the R version. You may have +noticed the conversion also created C versions of the first +derivative. This is done automatically and gives not just C versions +of function, but C versions of the derivatives and registers them with +`rxode2`. This allows the C versions to work with not only `rxode2` +but `nlmixr2` models. This function was setup in advance to allow this type of conversion. In general the derivatives will be calculated if there is not a `return()` statement in the user defined function. This means simply let R return the last value instead of explictly calling out the `return()`. Many people prefer this method of coding. @@ -90,41 +105,60 @@ f_R <- function(actRad, k_0, a_k) { rxFun(f_R) ``` -While this is still helpful because some functions have early returns, the `nlmixr2` models requiring derivatives would be calculated be non-optimized finite differences when this occurs. While this gets into the internals of `rxode2` and `nlmixr2` you can see this more easily when calculating the derivatives: +While this is still helpful because some functions have early returns, +the `nlmixr2` models requiring derivatives would be calculated be +non-optimized finite differences when this occurs. While this gets +into the internals of `rxode2` and `nlmixr2` you can see this more +easily when calculating the derivatives: ```{r derExample} rxFromSE("Derivative(f_R(actRad, k_0, a_k),k_0)") ``` -Whereas the originally defined function `newAbs()` would use the new derivatives calculated as well: +Whereas the originally defined function `newAbs()` would use the new +derivatives calculated as well: ```{r derFromC} rxFromSE("Derivative(newAbs(x),x)") ``` -In some circumstances, the conversion to C is not possible, though you can still use the R function. +In some circumstances, the conversion to C is not possible, though you +can still use the R function. -There are some requirements for R functions to be integrated into the rxode2 system: +There are some requirements for R functions to be integrated into the +rxode2 system: -- The function must have a set number of arguments, variable arguments like `f(…)` are currently not allowed. +- The function must have a set number of arguments, variable + arguments like `f(…)` are currently not allowed. -- The function is given each argument as a single number, and the function should return a single number +- The function is given each argument as a single number, and the + function should return a single number -If these requirements are met you can use the R function in rxode2. Additional requirements for conversion to C include: +If these requirements are met you can use the R function in +rxode2. Additional requirements for conversion to C include: -- Any functions that you use within the R function must be understood and available to `rxode2`. +- Any functions that you use within the R function must be + understood and available to `rxode2`. - - Practically speaking if you have `fun2()` which refers to `fun1()`, `fun1()` must be changed to C code and available to `rxode2` before changing the function `fun2()` to C. + - Practically speaking if you have `fun2()` which refers to + `fun1()`, `fun1()` must be changed to C code and available to + `rxode2` before changing the function `fun2()` to C. -- The functions can include `if`/`else` assignments or simple return statements (either by returning a value or having that value on a line by itself). Special R control structures and functions (like `for` and `lapply`) cannot be present. +- The functions can include `if`/`else` assignments or simple return + statements (either by returning a value or having that value on a + line by itself). Special R control structures and functions (like + `for` and `lapply`) cannot be present. - The function cannot refer to any package functions -- As mentioned, if the `return()` statement is present, the derivative C functions and `rxode2`'s derivative table is not updated. +- As mentioned, if the `return()` statement is present, the + derivative C functions and `rxode2`'s derivative table is not + updated. ## C based functions -You can add your own C functions directly into rxode2 as well using `rxFun()`: +You can add your own C functions directly into rxode2 as well using +`rxFun()`: ```{r rxFun} fun <- " @@ -133,7 +167,7 @@ fun <- " } " ## C-code for function -rxFun("fun", c("a", "b", "c"), fun) +rxFun("fun", c("a", "b", "c"), fun) ``` If you wanted you could also use C functions or expressions for the derivatives by using the `rxD()` function: @@ -152,7 +186,8 @@ rxD("fun", list( )) ``` -Removing the function with `rxRmFun()` will also remove the derivative table: +Removing the function with `rxRmFun()` will also remove the derivative +table: ```{r rxDrm} rxRmFun("fun")