More than one level of nesting is possible in RxODE; In this example we will be using the following uncertainties and sources of variability:
| Level | Variable | Matrix specified | Integrated Matrix | 
|---|---|---|---|
| Model uncertainty | NA | thetaMat | thetaMat | 
| Investigator | inv.Cl,inv.Ka | omega | theta | 
| Subject | eta.Cl,eta.Ka | omega | omega | 
| Eye | eye.Cl,eye.Ka | omega | omega | 
| Occasion | iov.Cl,occ.Ka | omega | omega | 
| Unexplained Concentration | prop.sd | sigma | sigma | 
| Unexplained Effect | add.sd | sigma | sigma | 
This event table contains nesting variables:
#> RxODE 1.1.1 using 1 threads (see ?getRxThreads)
#>   no cache: create with `rxCreateCache()`#> 
#> Attaching package: 'dplyr'#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
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(seq(0, 240, by=4)) %>% # Assumes sampling when there is no dosing information
  et(seq(0, 240, by=4) + 0.1) %>% ## adds 0.1 for separate eye
  et(id=1:20) %>%
  ## Add an occasion per dose
  mutate(occ=cumsum(!is.na(amt))) %>%
  mutate(occ=ifelse(occ == 0, 1, occ)) %>%
  mutate(occ=2- occ %% 2) %>%
  mutate(eye=ifelse(round(time) == time, 1, 2)) %>%
  mutate(inv=ifelse(id < 10, 1, 2)) %>% as_tibble ->
  evThis creates the RxODE model with multi-level nesting. Note the variables inv.Cl, inv.Ka, eta.Cl etc; You only need one variable for each level of nesting.
mod <- RxODE({
  ## Clearance with individuals
  eff(0) = 1
  C2 = centr/V2*(1+prop.sd);
  C3 = peri/V3;
  CL =  TCl*exp(eta.Cl + eye.Cl + iov.Cl + inv.Cl)
  KA = TKA * exp(eta.Ka + eye.Ka + iov.Cl + inv.Ka)
  d/dt(depot) =-KA*depot;
  d/dt(centr) = KA*depot - CL*C2 - Q*C2 + Q*C3;
  d/dt(peri)  =                    Q*C2 - Q*C3;
  d/dt(eff)  = Kin - Kout*(1-C2/(EC50+C2))*eff;
  ef0 = eff + add.sd
})
theta <- c("TKA"=0.294, "TCl"=18.6, "V2"=40.2,
           "Q"=10.5, "V3"=297, "Kin"=1, "Kout"=1, "EC50"=200)
## Creating covariance matrix
tmp <- matrix(rnorm(8^2), 8, 8)
tMat <- tcrossprod(tmp, tmp) / (8 ^ 2)
dimnames(tMat) <- list(names(theta), names(theta))
tMat#>               TKA           TCl           V2             Q            V3
#> TKA   0.052299027 -0.0020034683 -0.013430812  0.0042390076  0.0413906822
#> TCl  -0.002003468  0.0218331047  0.002766279  0.0182346413 -0.0332541792
#> V2   -0.013430812  0.0027662795  0.078878019  0.0428913911 -0.0064044043
#> Q     0.004239008  0.0182346413  0.042891391  0.0688584959  0.0005038676
#> V3    0.041390682 -0.0332541792 -0.006404404  0.0005038676  0.1168521908
#> Kin  -0.028991201  0.0249455744  0.019150688  0.0346070136 -0.0700758592
#> Kout  0.003501976 -0.0009969396 -0.047376005  0.0044577667  0.0140943439
#> EC50 -0.012011849 -0.0314580393 -0.079212914 -0.0642195971  0.0287538400
#>               Kin          Kout        EC50
#> TKA  -0.028991201  0.0035019757 -0.01201185
#> TCl   0.024945574 -0.0009969396 -0.03145804
#> V2    0.019150688 -0.0473760047 -0.07921291
#> Q     0.034607014  0.0044577667 -0.06421960
#> V3   -0.070075859  0.0140943439  0.02875384
#> Kin   0.106305332  0.0091986293 -0.04788276
#> Kout  0.009198629  0.0845471861  0.06074777
#> EC50 -0.047882765  0.0607477694  0.16205720To specify multiple levels of nesting, you can specify it as a nested lotri matrix; When using this approach you use the condition operator | to specify what variable nesting occurs on; For the Bayesian simulation we need to specify how much information we have for each parameter; For RxODE this is the nu parameter.
In this case: - id, nu=100 or the model came from 100 subjects - eye, nu=200 or the model came from 200 eyes - occ, nu=200 or the model came from 200 occasions - inv, nu=10 or the model came from 10 investigators
To specify this in lotri you can use | var(nu=X), or:
omega <- lotri(lotri(eta.Cl ~ 0.1,
                     eta.Ka ~ 0.1) | id(nu=100),
               lotri(eye.Cl ~ 0.05,
                     eye.Ka ~ 0.05) | eye(nu=200),
               lotri(iov.Cl ~ 0.01,
                     iov.Ka ~ 0.01) | occ(nu=200),
               lotri(inv.Cl ~ 0.02,
                     inv.Ka ~ 0.02) | inv(nu=10))
omega#> $id
#>        eta.Cl eta.Ka
#> eta.Cl    0.1    0.0
#> eta.Ka    0.0    0.1
#> 
#> $eye
#>        eye.Cl eye.Ka
#> eye.Cl   0.05   0.00
#> eye.Ka   0.00   0.05
#> 
#> $occ
#>        iov.Cl iov.Ka
#> iov.Cl   0.01   0.00
#> iov.Ka   0.00   0.01
#> 
#> $inv
#>        inv.Cl inv.Ka
#> inv.Cl   0.02   0.00
#> inv.Ka   0.00   0.02
#> 
#> Properties: nuThe last piece of variability to specify is the unexplained variability
sigma <- lotri(prop.sd ~ .25,
               add.sd~ 0.125)
s <- rxSolve(mod, theta, ev,
             thetaMat=tMat, omega=omega,
             sigma=sigma, sigmaDf=400,
             nStud=400)#> unhandled error message: EE:[lsoda] 70000 steps taken before reaching tout
#>  @(lsoda.c:749#> Warning: some ID(s) could not solve the ODEs correctly; These values are
#> replaced with 'NA'
print(s)#> ______________________________ Solved RxODE object _____________________________
#> -- Parameters ($params): -------------------------------------------------------
#> # A tibble: 8,000 x 24
#>    sim.id id    `inv.Cl(inv==1)` `inv.Cl(inv==2)` `inv.Ka(inv==1)`
#>     <int> <fct>            <dbl>            <dbl>            <dbl>
#>  1      1 1             -0.00275          -0.0420           -0.151
#>  2      1 2             -0.00275          -0.0420           -0.151
#>  3      1 3             -0.00275          -0.0420           -0.151
#>  4      1 4             -0.00275          -0.0420           -0.151
#>  5      1 5             -0.00275          -0.0420           -0.151
#>  6      1 6             -0.00275          -0.0420           -0.151
#>  7      1 7             -0.00275          -0.0420           -0.151
#>  8      1 8             -0.00275          -0.0420           -0.151
#>  9      1 9             -0.00275          -0.0420           -0.151
#> 10      1 10            -0.00275          -0.0420           -0.151
#> # ... with 7,990 more rows, and 19 more variables: inv.Ka(inv==2) <dbl>,
#> #   eye.Cl(eye==1) <dbl>, eye.Cl(eye==2) <dbl>, eye.Ka(eye==1) <dbl>,
#> #   eye.Ka(eye==2) <dbl>, iov.Cl(occ==1) <dbl>, iov.Cl(occ==2) <dbl>,
#> #   iov.Ka(occ==1) <dbl>, iov.Ka(occ==2) <dbl>, V2 <dbl>, V3 <dbl>, TCl <dbl>,
#> #   eta.Cl <dbl>, TKA <dbl>, eta.Ka <dbl>, Q <dbl>, Kin <dbl>, Kout <dbl>,
#> #   EC50 <dbl>
#> -- Initial Conditions ($inits): ------------------------------------------------
#> depot centr  peri   eff 
#>     0     0     0     1 
#> 
#> Simulation with uncertainty in:
#> * parameters (s$thetaMat for changes)
#> * omega matrix (s$omegaList)
#> 
#> -- First part of data (object): ------------------------------------------------
#> # A tibble: 976,000 x 18
#>   sim.id    id  time   inv.Cl inv.Ka eye.Cl eye.Ka iov.Cl  iov.Ka    C2       C3
#>    <int> <int>   [h]    <dbl>  <dbl>  <dbl>  <dbl>  <dbl>   <dbl> <dbl>    <dbl>
#> 1      1     1   0   -0.00275 -0.151 0.0266 0.313   0.134 -0.0798 0     0       
#> 2      1     1   0.1 -0.00275 -0.151 0.457  0.0464  0.134 -0.0798 0.664 0.000843
#> 3      1     1   4   -0.00275 -0.151 0.0266 0.313   0.134 -0.0798 3.37  0.342   
#> 4      1     1   4.1 -0.00275 -0.151 0.457  0.0464  0.134 -0.0798 4.58  0.352   
#> 5      1     1   8   -0.00275 -0.151 0.0266 0.313   0.134 -0.0798 5.06  0.717   
#> 6      1     1   8.1 -0.00275 -0.151 0.457  0.0464  0.134 -0.0798 4.41  0.725   
#> # ... with 975,994 more rows, and 7 more variables: CL <dbl>, KA <dbl>,
#> #   ef0 <dbl>, depot <dbl>, centr <dbl>, peri <dbl>, eff <dbl>
#> ________________________________________________________________________________There are multiple investigators in a study; Each investigator has a number of individuals enrolled at their site. RxODE automatically determines the number of investigators and then will simulate an effect for each investigator. With the output, inv.Cl(inv==1) will be the inv.Cl for investigator 1, inv.Cl(inv==2) will be the inv.Cl for investigator 2, etc.
inv.Cl(inv==1), inv.Cl(inv==2), etc will be simulated for each study and then combined to form the between investigator variability. In equation form these represent the following:
inv.Cl = (inv == 1) * `inv.Cl(inv==1)` + (inv == 2) * `inv.Cl(inv==2)`If you look at the simulated parameters you can see inv.Cl(inv==1) and inv.Cl(inv==2) are in the s$params; They are the same for each study:
#>   sim.id id inv.Cl(inv==1) inv.Cl(inv==2) inv.Ka(inv==1) inv.Ka(inv==2)
#> 1      1  1   -0.002747036    -0.04199234     -0.1511898     0.09129996
#> 2      1  2   -0.002747036    -0.04199234     -0.1511898     0.09129996
#> 3      1  3   -0.002747036    -0.04199234     -0.1511898     0.09129996
#> 4      1  4   -0.002747036    -0.04199234     -0.1511898     0.09129996
#> 5      1  5   -0.002747036    -0.04199234     -0.1511898     0.09129996
#> 6      1  6   -0.002747036    -0.04199234     -0.1511898     0.09129996
#>   eye.Cl(eye==1) eye.Cl(eye==2) eye.Ka(eye==1) eye.Ka(eye==2) iov.Cl(occ==1)
#> 1     0.02663260     0.45652885     0.31266166     0.04643933    0.133931213
#> 2    -0.00645066    -0.14663791    -0.05418058     0.46416699   -0.187409314
#> 3    -0.19104833     0.28809622    -0.21654429     0.23997922    0.028992966
#> 4    -0.43362901     0.18609466    -0.28564274    -0.25316655    0.043293203
#> 5     0.20127512     0.14003835     0.06926179     0.02192560    0.006925008
#> 6     0.44923971     0.06974016    -0.16320977    -0.11844843    0.108659686
#>   iov.Cl(occ==2) iov.Ka(occ==1) iov.Ka(occ==2)       V2       V3     TCl
#> 1    0.056467287   -0.079792617    -0.02431260 40.29231 296.7368 18.7175
#> 2   -0.027264704   -0.056838177    -0.11527060 40.29231 296.7368 18.7175
#> 3    0.001101861   -0.002305014    -0.02606005 40.29231 296.7368 18.7175
#> 4   -0.040806968    0.052022440    -0.08489036 40.29231 296.7368 18.7175
#> 5   -0.167999980   -0.075263205     0.04186347 40.29231 296.7368 18.7175
#> 6    0.046880336    0.009432103    -0.06332094 40.29231 296.7368 18.7175
#>        eta.Cl        TKA      eta.Ka        Q     Kin      Kout     EC50
#> 1  0.05249875 0.02854144 -0.66296533 10.50871 1.19586 0.7642861 199.6414
#> 2  0.69046590 0.02854144  0.34608629 10.50871 1.19586 0.7642861 199.6414
#> 3 -0.16526149 0.02854144  0.07753312 10.50871 1.19586 0.7642861 199.6414
#> 4  0.17141880 0.02854144  0.07579197 10.50871 1.19586 0.7642861 199.6414
#> 5  0.04265318 0.02854144  0.09043223 10.50871 1.19586 0.7642861 199.6414
#> 6  0.04398132 0.02854144  0.41274350 10.50871 1.19586 0.7642861 199.6414#>   sim.id id inv.Cl(inv==1) inv.Cl(inv==2) inv.Ka(inv==1) inv.Ka(inv==2)
#> 1      2  1      0.2142626    0.005337268      0.2257368    -0.06238657
#> 2      2  2      0.2142626    0.005337268      0.2257368    -0.06238657
#> 3      2  3      0.2142626    0.005337268      0.2257368    -0.06238657
#> 4      2  4      0.2142626    0.005337268      0.2257368    -0.06238657
#> 5      2  5      0.2142626    0.005337268      0.2257368    -0.06238657
#> 6      2  6      0.2142626    0.005337268      0.2257368    -0.06238657
#>   eye.Cl(eye==1) eye.Cl(eye==2) eye.Ka(eye==1) eye.Ka(eye==2) iov.Cl(occ==1)
#> 1    -0.28637459    -0.32602143    -0.18435100    -0.06883430    -0.11106234
#> 2     0.34495061     0.01464476     0.16817239    -0.04083867    -0.01601272
#> 3     0.24400619     0.19866998    -0.04173507    -0.29629002    -0.13689397
#> 4     0.02743539     0.05776011    -0.24078054     0.04593929     0.02620149
#> 5     0.19090509    -0.16212950     0.49114346     0.10336253    -0.13556974
#> 6    -0.15327550    -0.09805926     0.11269492    -0.01609979     0.02763238
#>   iov.Cl(occ==2) iov.Ka(occ==1) iov.Ka(occ==2)       V2       V3      TCl
#> 1     0.13902745    0.003094429     0.03594814 40.16754 297.1583 18.46715
#> 2    -0.02666789    0.007220282    -0.06790929 40.16754 297.1583 18.46715
#> 3     0.11351119   -0.086691401    -0.06195628 40.16754 297.1583 18.46715
#> 4     0.01901208   -0.112879021     0.18574793 40.16754 297.1583 18.46715
#> 5    -0.03040496   -0.006146741     0.03085491 40.16754 297.1583 18.46715
#> 6    -0.12782711    0.043930861    -0.08498676 40.16754 297.1583 18.46715
#>        eta.Cl       TKA      eta.Ka       Q       Kin      Kout     EC50
#> 1 -0.40789384 0.3212433 -0.07189073 10.3295 0.9591919 0.9804559 200.2417
#> 2  0.11494752 0.3212433  0.30166435 10.3295 0.9591919 0.9804559 200.2417
#> 3 -0.07089084 0.3212433 -0.31349280 10.3295 0.9591919 0.9804559 200.2417
#> 4  0.25526236 0.3212433 -0.67862826 10.3295 0.9591919 0.9804559 200.2417
#> 5 -0.42579910 0.3212433 -0.18178978 10.3295 0.9591919 0.9804559 200.2417
#> 6 -0.24397398 0.3212433  0.28921473 10.3295 0.9591919 0.9804559 200.2417For between eye variability and between occasion variability each individual simulates a number of variables that become the between eye and between occasion variability; In the case of the eye:
eye.Cl = (eye == 1) * `eye.Cl(eye==1)` + (eye == 2) * `eye.Cl(eye==2)`So when you look the simulation each of these variables (ie eye.Cl(eye==1), eye.Cl(eye==2), etc) they change for each individual and when combined make the between eye variability or the between occasion variability that can be seen in some pharamcometric models.