rxode2 is an R package for solving and simulatingfrom ode-based models. These models are convert the rxode2 mini-languageto C and create a compiled dll for fast solving. ODE solving usingrxode2 has a few key parts:
rxode2() which creates the C code for fast ODE solvingbased on asimplesyntax related to Leibnitz notation.NONMEM ordeSolvecompatibledata frame, oret() oreventTable() foreasysimulation of eventsiCov= as needed)rxSolve() which solves the system of equations usinginitial conditions and parameters to make predictionsYou can install the released version of rxode2 fromCRAN with:
install.packages("rxode2")The fastest way to install the development version ofrxode2 is to use ther-universe service. Thisservice compiles binaries of the development version for MacOS and forWindows so you don’t have to wait for package compilation:
install.packages(c("dparser","rxode2ll","rxode2"),repos=c(nlmixr2="https://nlmixr2.r-universe.dev",CRAN="https://cloud.r-project.org"))If this doesn’t work you install the development version of rxode2with
devtools::install_github("nlmixr2/rxode2ll")devtools::install_github("nlmixr2/rxode2")To build models with rxode2, you need a working c compiler. To useparallel threaded solving in rxode2, this c compiler needs to supportopen-mp.
You can check to see if R has working c compiler you can checkwith:
## install.packages("pkgbuild")pkgbuild::has_build_tools(debug =TRUE)If you do not have the toolchain, you can set it up as described bythe platform information below:
In windows you may simply use installr to install rtools:
install.packages("installr")library(installr)install.rtools()Alternatively you candownload andinstall rtools directly.
To get the most speed you need OpenMP enabled and compile rxode2 withthat compiler. There are various options and the most up to datediscussion about this is likely thedata.tableinstallation FAQ for MacOS. The last thing to keep in mind is thatrxode2 uses the code very similar to the originallsoda which requires thegfortran compiler tobe setup as well as theOpenMP compilers.
If you are going to be usingrxode2 andnlmixr together and have an older mac computer, I wouldsuggest trying the following:
library(symengine)If this crashes your R session then the binary does not work withyour Mac machine. To be able to run nlmixr, you will need to compilethis package manually. I will proceed assuming you havehomebrew installed on your system.
On your system terminal you will need to install the dependencies tocompilesymengine:
brew install cmake gmp mpfr libmpcAfter installing the dependencies, you need to re-installsymengine:
install.packages("symengine",type="source")library(symengine)To install on linux make sure you installgcc (withopenmp support) andgfortran using your distribution’spackage manager.
You will also have to install system dependencies likeudunits and thesymenginedependencies for the complete installation to work in linux. Youcould also have this done by system packages in your package manager ifyou add the appropriate repositories. This is the point of ther2u project.
For installation on R versions 4.0.x and 4.1.x, please see theinstructions on how to installsymengine in thenlmixr2 installation instructions:https://github.com/nlmixr2/nlmixr2#r-package-installation
Since the development version of rxode2 uses StanHeaders, you willneed to make sure your compiler is setup to support C++14, as describedin therstansetup page. For R 4.0, I do not believe this requires modifying thewindows toolchain any longer (so it is much easier to setup).
Once the C++ toolchain is setup appropriately, you can install thedevelopment version fromGitHub with:
# install.packages("devtools")devtools::install_github("nlmixr2/rxode2ll")devtools::install_github("nlmixr2/rxode2")The model equations can be specified through a text string, a modelfile or an R expression. Both differential and algebraic equations arepermitted. Differential equations are specified byd/dt(var_name) =. Each equation can be separated by asemicolon.
To loadrxode2 package and compile the model:
library(rxode2)#> rxode2 3.0.4.9000 using 8 threads (see ?getRxThreads)mod1<-function() {ini({# central KA=2.94E-01 CL=1.86E+01 V2=4.02E+01# peripheral Q=1.05E+01 V3=2.97E+02# effects Kin=1 Kout=1 EC50=200 })model({ C2<- centr/V2 C3<- peri/V3 d/dt(depot)<--KA*depot d/dt(centr)<- KA*depot- CL*C2- Q*C2+ Q*C3 d/dt(peri)<- Q*C2- Q*C3eff(0)<-1 d/dt(eff)<- Kin- Kout*(1-C2/(EC50+C2))*eff })}Model parameters may be specified in theini({}) modelblock, initial conditions can be specified within the model with thecmt(0)= X, like in this modeleff(0) <- 1.
You may also specify between subject variability initial conditionsand residual error components just like nlmixr2. This allows a singleinterface fornlmixr2/rxode2 models. Alsonote, the classicrxode2 interface still works just like itdid in the past (so don’t worry about breaking code at this time).
In fact, you can get the classicrxode2 model$simulationModel in the ui object:
mod1<-mod1()# create the ui object (can also use `rxode2(mod1)`)mod1summary(mod1$simulationModel)rxode2 provides a simple and very flexible way tospecify dosing and sampling through functions that generate an eventtable. First, an empty event table is generated through the “et()”function. This has an interface that is similar to NONMEM eventtables:
ev<-et(amountUnits="mg",timeUnits="hours")%>%et(amt=10000,addl=9,ii=12,cmt="depot")%>%et(time=120,amt=2000,addl=4,ii=14,cmt="depot")%>%et(0:240)# Add samplingYou can see from the above code, you can dose to the compartmentnamed in the rxode2 model. This slight deviation from NONMEM can reducethe need for compartment renumbering.
These events can also be combined and expanded (to multi-subjectevents and complex regimens) withrbind,c,seq, andrep. For more information aboutcreating complex dosing regimens using rxode2 see therxode2events vignette.
The ODE can now be solved usingrxSolve:
x<- mod1%>%rxSolve(ev)#> ℹ parameter labels from comments are typically ignored in non-interactive mode#> ℹ Need to run with the source intact to parse comments#> → creating rxode2 include directory#> → getting R compile options#> → precompiling headers#> ✔ done#> using C compiler: 'gcc.exe (GCC) 14.2.0'x#> ── Solved rxode2 object ──#> ── Parameters (x$params): ──#> KA CL V2 Q V3 Kin Kout EC50#> 0.294 18.600 40.200 10.500 297.000 1.000 1.000 200.000#> ── Initial Conditions (x$inits): ──#> depot centr peri eff#> 0 0 0 1#> ── First part of data (object): ──#> # A tibble: 241 × 7#> time C2 C3 depot centr peri eff#> [h] <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>#> 1 0 0 0 10000 0 0 1#> 2 1 44.4 0.920 7453. 1784. 273. 1.08#> 3 2 54.9 2.67 5554. 2206. 794. 1.18#> 4 3 51.9 4.46 4140. 2087. 1324. 1.23#> 5 4 44.5 5.98 3085. 1789. 1776. 1.23#> 6 5 36.5 7.18 2299. 1467. 2132. 1.21#> # ℹ 235 more rowsThis returns a modified data frame. You can see the compartmentvalues in the plot below:
library(ggplot2)plot(x,C2)+ylab("Central Concentration")
Or,
plot(x,eff)+ylab("Effect")
Note that the labels are automatically labeled with the units fromthe initial event table. rxode2 extractsunits to label theplot (if they are present).
This is a brief comparison of pharmacometric ODE solving R packagestorxode2.
There are severalR packagesfor differential equations. The most popular isdeSolve.
However for pharmacometrics-specific ODE solving, there are only 2packages other thanrxode2 released onCRAN. Each uses compiled code to have faster ODE solving.
mrgsolve, whichuses C++ lsoda solver to solve ODE systems. The user is required towrite hybrid R/C++ code to create a mrgsolve model which is translatedto C++ for solving.
In contrast,rxode2 has a R-like mini-language that isparsed into C code that solves the ODE system.
Unlikerxode2,mrgsolve does not currentlysupport symbolic manipulation of ODE systems, like automatic Jacobiancalculation or forward sensitivity calculation (rxode2currently supports this and this is the basis ofnlmixr2’s FOCEialgorithm)
dMod, whichuses a unique syntax to create “reactions”. These reactions create theunderlying ODEs and then created c code for a compiled deSolvemodel.
In contrastrxode2 defines ODE systems at a lower level.rxode2’s parsing of the mini-language comes from C, whereasdMod’s parsing comes from R.
Likerxode2,dMod supports symbolicmanipulation of ODE systems and calculates forward sensitivities andadjoint sensitivities of systems.
Unlikerxode2,dMod is not thread-safesincedeSolve is not yet thread-safe.
PKPDsim whichdefines models in an R-like syntax and converts the system to compiledcode.
Likemrgsolve,PKPDsim does not currentlysupport symbolic manipulation of ODE systems.
PKPDsim is not thread-safe.
The open pharmacometrics open source community is fairly friendly,and the rxode2 maintainers has had positive interactions with all of theODE-solving pharmacometric projects listed.
rxode2 supports 1-3 compartment models with gradients(using stan math’s auto-differentiation). This currently uses the sameequations asPKADVAN to allow time-varying covariates.
rxode2 can mix ODEs and solved systems.
mrgsolvecurrently has 1-2 compartment (poly-exponential models) models built-in.The solved systems and ODEs cannot currently be mixed.
pmxToolscurrently have 1-3 compartment (super-positioning) models built-in. Thisis a R-only implementation.
PKPDsim uses1-3 “ADVAN” solutions using non-superpositioning.
PKPDmodels hasa one-compartment model with gradients.