User-defined functions

In this example we implementation a user-defined function for the one-compartment model. The function takes time and elimination rate constant arguments and outputs the drug amount a given time, so that one can use it as

1
2
3
4
5
6
7
  $PRED
    ;#...
    VECTRA(1)=THETA(1)*EXP(ETA(1))
    VECTRA(2)=TIME
    ;#...
    A=DOSE*FUNCA(VECTRA)
    ;#...

We define the function in Fortran as below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
  FUNCTION FUNCA(X,X1,X2)
    ! Implements the One Compartment Linear model
    USE SIZES, ONLY: DPSIZE
    REAL(KIND=DPSIZE), INTENT(IN)     :: X
    REAL(KIND=DPSIZE), INTENT(IN OUT) :: X1,X2
    REAL(KIND=DPSIZE) :: FUNCA
    DIMENSION :: X(9),X1(9),X2(9,9)
    REAL(KIND=DPSIZE) :: EXPT
    ! THE FUNCTION ITSELF
    EXPT=EXP(-X(1)*X(2))
    FUNCA=EXPT
    ! 1ST. PARTIALS
    X1(1)=-EXPT*X(2)
    X1(2)=-EXPT*X(1)
    ! 2ND. PARTIALS
    X2(1,1)=EXPT*X(2)*X(2)
    X2(1,2)=EXPT*X(1)*X(2)
    X2(2,1)=EXPT*X(1)*X(2)
    X2(2,2)=EXPT*X(1)*X(1)
    RETURN
  END FUNCTION FUNCA

Note that the function definition requires calculation of the first- and second-order derivatives with respect to the arguments (elimination rate and time in this case).

To provide the above function definition (assumed stored in file "ONE_COMPARTMENT_LINEAR.f90") to NONMEM, we supply its file to NONMEM in $SUBROUTINE record:

1
 $SUBROUTINES OTHER=ONE_COMPARTMENT_LINEAR.f90

To to make the model more readable, one can $ABBREVIATED REPLACE:

1
2
3
4
5
6
7
8
 $ABBR REPLACE ONE_COMPARTMENT_LINEAR=FUNCA
    ...
 $PRED
    ...
    VECTRA(1)=THETA(1)*EXP(ETA(1))
    VECTRA(2)=TIME
    ...
    A=DOSE*ONE_COMPARTMENT_LINEAR(VECTRA)

Alternatively, one can use $ABBREVIATED FUNCTION to declare the function

1
2
3
4
5
6
7
8
 $ABBR FUNCTION ONE_COMPARTMENT_LINEAR(KTIME,2)
      ...
 $PRED
    ...
    KTIME(1)=THETA(1)*EXP(ETA(1))
    KTIME(2)=TIME
    ...
    A=DOSE*ONE_COMPARTMENT_LINEAR(KTIME)

Note that here the vector variable is no longer the reserved VECTRA but the KTIME declared in $ABBR FUNCTION. In this case the Fortran definition must match the declared function name:

1
2
3
4
5
6
7
  FUNCTION ONE_COMPARTMENT_LINEAR(X,X1,X2)
    USE SIZES, ONLY: DPSIZE
    REAL(KIND=DPSIZE), INTENT(IN)     :: X
    REAL(KIND=DPSIZE), INTENT(IN OUT) :: X1,X2
    REAL(KIND=DPSIZE) :: ONE_COMPARTMENT_LINEAR
    DIMENSION :: X(9),X1(9),X2(9,9)
    ! ...

Multiple functions can be used with the $ABBREVIATED REPLACE feature, same for $ABBREVIATED FUNCTION. Suppose two functions, RED and GREEN are needed:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
 $SUBR OTHER=red.f90 OTHER=green.f90
  ...
 $ABBR REPLACE RED=FUNCA
 $ABBR REPLACE GREEN=FUNCB
  ...
 $PRED
  ...
    VECTRA(1)=THETA(1)*EXP(ETA(1))
    VECTRA(2)=TIME
    A=DOSE*RED(VECTRA)
    B=DOSE*GREEN(VECTRA)
  ...

With the file "red.f90" for the definition for FUNCA, and "green.f90" for FUNCB.

Similar to $ABBREVIATED FUNCTION, the $ABBREVIATED REPLACE can be used to provide more meaningful names for reserved vectors. For example, suppose the arguments of the functions are different vectors.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 $ABBR REPLACE RED=FUNCA, REDARG=VECTRA
 $ABBR REPLACE GREEN=FUNCB, GREENARG=VECTRB
  ...
 $PRED
  ...
    REDARG(1)=...
    REDARG(2)=...
    GREENARG(1)=...
    GREENARG(2)=...
    A=DOSE*RED(REDARG)
    B=DOSE*GREEN(GREENARG)