= 70, TVCL = 1.2
$PARAM WT
$PKdouble CL = TVCL * pow(WT/70, 0.75);
9 Plugins
9.1 autodec
Available as of mrgsolve version 1.0.0.
When this plugin is invoked, mrgsolve will search your model code for assignments and automatically declare them as double
precision numbers. The following blocks are searched
$PREAMBLE
$MAIN
(or$PK
)$ODE
(or$DES
)$TABLE
(or$ERROR
)$PRED
For example, the following code requires that CL
gets assigned a type
This is the default mrgsolve behavior and has been since the beginning.
The autodec
plugin lets you write the following
$PLUGIN autodec
= 70, TVCL = 1.2
$PARAM WT
$PK= TVCL * pow(WT/70, 0.75); CL
mrgsolve will find CL = ...
and understand that this is a user initiated variable and will declare it as double
for you. Don’t worry about WT = 70
in $PARAM
; mrgsolve should already know about that won’t try to declare it.
When you are using the autodec
plugin, you can still declare variables as double
or int
or bool
. mrgsolve already finds those variables and will understand to leave those declarations alone. Note that it may still very convenient to declare using the capture
type those variables that you want captured into the output
$PLUGIN autodec
$ERROR= IPRED * exp(EPS(1)); capture Y
The capture
typedef makes Y
a double
; we didn’t need to declare it with autodec
in play, but decided to declare with capture
so that it is copied into the simulated output.
The autodec
plugin is intended for more straightforward models where most / all variables are real valued. Because mrgsolve can handle any valid C++ code in these blocks, there is a possibility that the code could get much more complicated, including custom classes and methods. In this case, we recommend to bypass this feature and take control of declaring variables as you would in the default mode.
In case mrgsolve does try to declare (as double
) a variable that shouldn’t be handled that way, you can note this name in an environment variable inside your model called MRGSOLVE_AUTODEC_SKIP
= c("my_variable_1") $ENV MRGSOLVE_AUTODEC_SKIP
This can be a vector of variable names to NOT declare when autodec
is invoked.
9.2 nm-vars
Available as of mrgsolve version 1.0.0.
The nm-vars
plugin provides a more NONMEM-like set of macros to use when coding your compartmental model. Only a small subset of the NONMEM model syntax is replicated here.
F, R, D, ALAG
- To set bioavailability for the nth compartment, use
Fn
- To set the infusion rate for the nth compartment, use
Rn
- To set the infusion duration for the nth compartment, use
Dn
- To set the lag time for the nth compartment, use
ALAGn
For example
$CMT GUT CENT GUT2
$PK= 0.87; // equivalent to F_GUT = 0.87;
F1 = 2.25; // equivalent to R_CENT = 2.25;
R2 = 0.25; // equivalent to ALAG_GUT2 = 0.25; ALAG3
A, A_0, DADT
- To refer to the amount in the nth compartment, use
A(n)
- To refer to the initial amount in the nth compartment, use
A_0(n)
- To refer to the differential equation for the nth compartment, use
DADT(n)
For example
$CMT CMT1 CMT2
$PK(2) = 50;
A_0
$DES(1) = -KA * A(1);
DADT(2) = KA * A(1) - KE * A(2); DADT
Math
Starting with version 1.0.1, macros are provided for several math functions
EXP(a)
gets mapped toexp(a)
LOG(a)
gets mapped tolog(a)
SQRT(a)
gets mapped tosqrt(a)
These are purely for convenience, so that upper-case versions from NMTRAN don’t require conversion to lower-case; this happens automatically via the C++ preprocessor.
Other syntax
- Using
THETA(n)
in model code will resolve toTHETAn
; this feature is always available, even whennm-vars
hasn’t been invoked; we mention it here since it is a fundamental piece of the NONMEM syntax that mrgsolve has internalized - Use
T
in$DES
to refer to the current time in the odesolver rather thanSOLVERTIME
Reserved words with nm-vars is invoked
There are some additional reserved words when the nm-vars
plugin is invoked
A
A_0
DADT
T
It is an error to use one of these symbols as the name of a parameter or compartment or to try to declare them as variables.
mrgsolve syntax that is still required
There are a lot of differences remaining between mrgsolve and NONMEM syntax. We mention a few here to make the point
- mrgsolve continues to require
pow(base, exponent)
rather thanbase**exponent
- mrgsolve continues to require a semi-colon at the end of each statement (this is a C++ requirement)
- mrgsolve continues to require that user-defined variables are declared with a type, except when the
autodec
plugin (Section 9.1) is invoked
An example
There is an example of this syntax (along with autodec
features) in the internal model library
<- modlib("nm-like")
mod see(mod)
.
. Model file: nm-like.cpp
. $PROB Model written with some nonmem-like syntax features
.
. $PLUGIN nm-vars autodec
.
. $PARAM
. THETA1 = 1, THETA2 = 21, THETA3 = 1.3, WT = 70, F1I = 0.5, D2I = 2
. KIN = 100, KOUT = 0.1, IC50 = 10, IMAX = 0.9
.
. $CMT @number 3
.
. $PK
. CL = THETA(1) * pow(WT/70, 0.75);
. V = THETA(2);
. KA = THETA(3);
.
. F1 = F1I;
. D2 = D2I;
. A_0(3) = KIN / KOUT;
.
. $DES
. CP = A(2)/V;
. INH = IMAX*CP/(IC50 + CP);
.
. DADT(1) = -KA*A(1);
. DADT(2) = KA*A(1) - (CL/V)*A(2);
. DADT(3) = KIN * (1-INH) - KOUT * A(3);
.
. $ERROR
. CP = A(2)/V;
9.3 tad
Purpose Advanced calculation time after dose within your model. We call this “advanced” because it lets you track doses in multiple compartments. See the note below about a simpler way to calculate time after dose that should work fine if doses are only in a single compartment. This functionality is provided by mrgsolve.
Usage
First, tell mrgsolve
that you want to use the tad
plugin
$PLUGIN tad
The create tadose
objects, one for each compartment where you want to track time after dose. One approach is to do this in [ global ]
[plugin] tad
[ global ]
::tadose tad_cmt_1(1);
mrg::tadose tad_cmt_2(2); mrg
Notice that we pass the compartment number that we want to track in each case and also that we refer to the mrg::
namespace for the tadose
class.
The tadose
objects contain the following (public) members
cmt
the compartment to tracktold
the time of last dose; defaults to-1e9
had_dose
indicates if a dose has already been given for the current individualtad(self)
the function to call to calculate time after dose- the
self
object (Section 2.3.12) must be passed as the only argument - when the member function is called prior to the first administered dose, a value of
-1.0
is returned
- the
reset()
resets the state of the object; be sure to reset prior to simulating a new individual
As an example, you can call the reset()
method on one of the tadose
objects
.reset(); tad_cmt_1
You can find the source code for this object here.
A working example model that tracks doses in compartments 1
and 2
is provided here
[plugin] tad
[ global ]
::tadose tad_cmt_1(1);
mrg::tadose tad_cmt_2(2);
mrg
[ pkmodel ] cmt = "GUT,CENT", depot = TRUE
[ param ] CL = 1, V = 20, KA = 1
[ main ]
= tad_cmt_1.tad(self);
capture tad1 = tad_cmt_2.tad(self); capture tad2
Static approach
Another approach would be to make these static in [ main ]
but this approach would only work if you only use these in [ main ]
; the [ global ]
approach is preferable since then you can access the object in any block (function).
9.3.1 Note
Note there is a simpler way to calculate time after dose when only dosing into a single compartment
[ main ]
double tad = self.tad();
The self
object (Section 2.3.21) contains a tad()
member which will track time after dose. Note that this needs to be called every record.
9.4 CXX11
Purpose
Compile your model file with C++11
standard.
Usage
$PLUGIN CXX11
9.5 Rcpp
Purpose
Link to Rcpp
headers into your model.
Usage
$PLUGIN Rcpp
Note that once your model is linked to Rcpp
, you can start using that functionality immediately (without including Rcpp.h
).
A very useful feature provided by Rcpp
is that it exposes all of the dpqr
functions that you normally use in R (e.g. rnorm()
or runif()
). So, if you want to simulate a number from Uniform (0,1) you can write
$PLUGIN Rcpp
$TABLEdouble uni = R::runif(0,1);
Note that the arguments are the same as the R version (?runif
) except there is no n
argument; you always only get one draw.
Information about Rcpp
can be found here: https://github.com/RcppCore/Rcpp
9.6 mrgx
Compile in extra C++ / Rcpp functions that can be helpful to you for more advanced model coding. The mrgx
plugin is dependent on the Rcpp
plugin.
The functions provided by mrgx
are in a namespace of the same name, so to invoke these functions, you always prepend mrgx::
.
9.6.1 Get the model environment
Note that your model object (mod
) contains an R environment. For example
::house()@envir mrgsolve
. <environment: 0x11689c630>
The objects in this environment are created by a block called $ENV
in your model code (see Section 2.2.27);
To access this environment in your model, call
::Environment env = mrgx::get_envir(self); Rcpp
9.7 Extract an object from the model environment
When you have an object created in $ENV
[ env ]
<- rnorm(100) rand
You can extract this object with
[ preamble ]
::NumericVector draw = mrgx::get("rand", self); Rcpp
9.8 RcppArmadillo
Purpose
Link to RcppArmadillo
headers into your model.
Usage
$PLUGIN RcppArmadillo
Information about armadillo
can be found here: http://arma.sourceforge.net/ Information about RcppArmadillo
can be found here: https://github.com/RcppCore/RcppArmadillo
9.9 BH
Purpose
Link to boost
headers into your model.
Usage
$PLUGIN BH
Note that once your model is linked to BH
(boost
), you will be able to include the boost
header file that you need. You have to include the header file that contains the boost
function you want to use.
Information about boost
can be found here: https://boost.org. Information about BH
can be found here: https://github.com/eddelbuettel/bh