├── .Rprofile ├── .gitignore ├── BayesPBPK.Rproj ├── Dockerfile ├── Makefile ├── Project.toml ├── README.md ├── data └── Mavoglurant_A2121_nmpk.csv ├── deliv ├── figure │ ├── mavoPBPKGenODE │ │ ├── mavoPBPKGenODE-MCMCDiagnostics-Corrs.pdf │ │ ├── mavoPBPKGenODE-MCMCDiagnostics.pdf │ │ └── mavoPBPKGenODE-PPC.pdf │ ├── mavoPBPKGenODE_jl │ │ ├── DensPlots.pdf │ │ ├── MCMCTrace.pdf │ │ ├── PPCCond.pdf │ │ ├── PPCPred.pdf │ │ ├── PPCind.pdf │ │ ├── SimPred.pdf │ │ └── sensitivity.pdf │ ├── mavoPBPKLinODE │ │ ├── mavoPBPKLinODE-MCMCDiagnostics-Corrs.pdf │ │ ├── mavoPBPKLinODE-MCMCDiagnostics.pdf │ │ └── mavoPBPKLinODE-PPC.pdf │ └── mavoPBPKLinODE_jl │ │ ├── DensPlots.pdf │ │ ├── MCMCTrace.pdf │ │ ├── PPCCond.pdf │ │ └── PPCPred.pdf └── table │ ├── mavoPBPKGenODE │ └── mavoPBPKGenODE-ParameterTable.csv │ ├── mavoPBPKGenODE_jl │ ├── Quantiles.csv │ ├── Summary.csv │ └── mavoPBPKGenODE_jl-ParameterTable.csv │ ├── mavoPBPKLinODE │ └── mavoPBPKLinODE-ParameterTable.csv │ └── mavoPBPKLinODE_jl │ ├── Quantiles.csv │ └── Summary.csv ├── model ├── data.R ├── init.R ├── mavoPBPKGenODE.jl ├── mavoPBPKGenODE.stan ├── mavoPBPKGenODE │ └── mavoPBPKGenODE.fit.RDS ├── mavoPBPKGenODE_jl │ ├── df_params.csv │ ├── mavoPBPKGenODEchains.jls │ └── mavoPBPKGenODEchains_prior.jls ├── mavoPBPKLinODE.jl ├── mavoPBPKLinODE.stan ├── mavoPBPKLinODE │ └── mavoPBPKLinODE.fit.RDS ├── mavoPBPKLinODE_jl │ ├── mavoPBPKLinODEchains.jls │ └── mavoPBPKLinODEchains_prior.jls └── naphPBPKGenODE.stan ├── pkgs.R ├── renv.lock ├── renv ├── .gitignore └── activate.R └── script ├── .keep ├── getLinODEModel.R ├── mavoPBPKGenODE.R ├── mavoPBPKGenODE_jl_postprocess.R ├── mavoPBPKGenODE_run.jl ├── mavoPBPKLinODE.R ├── mavoPBPKLinODE_run.jl └── tools ├── cmdStanTools.R ├── functions.R └── stanTools.R /.Rprofile: -------------------------------------------------------------------------------- 1 | source("renv/activate.R") 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | .DS_Store 6 | script/Torsten/ 7 | -------------------------------------------------------------------------------- /BayesPBPK.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG DEFAULT_USER=bayes 2 | FROM alpine:3.15 as rootfs-stage 3 | ARG DEFAULT_USER 4 | 5 | # environment 6 | ENV REL=jammy 7 | ENV ARCH=amd64 8 | 9 | # install packages 10 | RUN \ 11 | apk add --no-cache \ 12 | bash \ 13 | curl \ 14 | tar \ 15 | tzdata \ 16 | xz \ 17 | git \ 18 | openssh 19 | 20 | 21 | # RUN git clone git@github.com:timknab/BayesPBPKTutorial.git 22 | RUN git clone https://github.com/metrumresearchgroup/BayesPBPK-tutorial.git BayesPBPKTutorial 23 | 24 | # Get base ubuntu files 25 | RUN git clone --branch jammy https://github.com/linuxserver/docker-baseimage-ubuntu.git 26 | # Get vscode files 27 | RUN git clone https://github.com/linuxserver/docker-code-server.git 28 | # Get rocker/rstudio files 29 | RUN git clone https://github.com/rocker-org/rocker-versioned2.git 30 | ## Set user 31 | RUN sed -i "s/abc/${DEFAULT_USER}/g" docker-baseimage-ubuntu/root/etc/s6-overlay/s6-rc.d/init-adduser/run 32 | RUN sed -i "s/abc/${DEFAULT_USER}/g" docker-code-server/root/etc/s6-overlay/s6-rc.d/init-code-server/run 33 | RUN sed -i "s/abc/${DEFAULT_USER}/g" docker-code-server/root/usr/local/bin/install-extension 34 | RUN sed -i "s/abc/${DEFAULT_USER}/g" docker-code-server/root/etc/s6-overlay/s6-rc.d/svc-code-server/run 35 | 36 | 37 | # Change user home 38 | RUN sed -i "s|cp /root/.bashrc /config/.bashrc| cp /root/.bashrc /home/${DEFAULT_USER}/.bashrc|g" docker-code-server/root/etc/s6-overlay/s6-rc.d/init-code-server/run 39 | 40 | 41 | 42 | # grab base tarball 43 | RUN \ 44 | mkdir /root-out && \ 45 | curl -o \ 46 | /rootfs.tar.gz -L \ 47 | https://partner-images.canonical.com/core/${REL}/current/ubuntu-${REL}-core-cloudimg-${ARCH}-root.tar.gz && \ 48 | tar xf \ 49 | /rootfs.tar.gz -C \ 50 | /root-out 51 | 52 | # set version for s6 overlay 53 | ARG S6_OVERLAY_VERSION="3.1.2.1" 54 | ARG S6_OVERLAY_ARCH="x86_64" 55 | 56 | # add s6 overlay 57 | ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp 58 | RUN tar -C /root-out -Jxpf /tmp/s6-overlay-noarch.tar.xz 59 | ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_OVERLAY_ARCH}.tar.xz /tmp 60 | RUN tar -C /root-out -Jxpf /tmp/s6-overlay-${S6_OVERLAY_ARCH}.tar.xz 61 | 62 | # add s6 optional symlinks 63 | ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-symlinks-noarch.tar.xz /tmp 64 | RUN tar -C /root-out -Jxpf /tmp/s6-overlay-symlinks-noarch.tar.xz 65 | ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-symlinks-arch.tar.xz /tmp 66 | RUN tar -C /root-out -Jxpf /tmp/s6-overlay-symlinks-arch.tar.xz 67 | 68 | # Runtime stage 69 | FROM scratch as ubuntu_base 70 | ARG DEFAULT_USER 71 | COPY --from=rootfs-stage /root-out/ / 72 | ARG BUILD_DATE 73 | ARG VERSION 74 | ARG MODS_VERSION="v3" 75 | LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DATE}" 76 | LABEL maintainer="TheLamer" 77 | 78 | ADD "https://raw.githubusercontent.com/linuxserver/docker-mods/mod-scripts/docker-mods.${MODS_VERSION}" "/docker-mods" 79 | 80 | # set environment variables 81 | ARG DEBIAN_FRONTEND="noninteractive" 82 | ENV HOME="/root" \ 83 | LANGUAGE="en_US.UTF-8" \ 84 | LANG="en_US.UTF-8" \ 85 | TERM="xterm" \ 86 | S6_CMD_WAIT_FOR_SERVICES_MAXTIME="0" \ 87 | S6_VERBOSITY=1 \ 88 | S6_STAGE2_HOOK=/docker-mods 89 | 90 | # copy sources 91 | COPY --from=rootfs-stage docker-baseimage-ubuntu/sources.list /etc/apt/ 92 | 93 | 94 | 95 | 96 | RUN \ 97 | echo "**** Ripped from Ubuntu Docker Logic ****" && \ 98 | set -xe && \ 99 | echo '#!/bin/sh' \ 100 | > /usr/sbin/policy-rc.d && \ 101 | echo 'exit 101' \ 102 | >> /usr/sbin/policy-rc.d && \ 103 | chmod +x \ 104 | /usr/sbin/policy-rc.d && \ 105 | dpkg-divert --local --rename --add /sbin/initctl && \ 106 | cp -a \ 107 | /usr/sbin/policy-rc.d \ 108 | /sbin/initctl && \ 109 | sed -i \ 110 | 's/^exit.*/exit 0/' \ 111 | /sbin/initctl && \ 112 | echo 'force-unsafe-io' \ 113 | > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup && \ 114 | echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' \ 115 | > /etc/apt/apt.conf.d/docker-clean && \ 116 | echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' \ 117 | >> /etc/apt/apt.conf.d/docker-clean && \ 118 | echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' \ 119 | >> /etc/apt/apt.conf.d/docker-clean && \ 120 | echo 'Acquire::Languages "none";' \ 121 | > /etc/apt/apt.conf.d/docker-no-languages && \ 122 | echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' \ 123 | > /etc/apt/apt.conf.d/docker-gzip-indexes && \ 124 | echo 'Apt::AutoRemove::SuggestsImportant "false";' \ 125 | > /etc/apt/apt.conf.d/docker-autoremove-suggests && \ 126 | mkdir -p /run/systemd && \ 127 | echo 'docker' \ 128 | > /run/systemd/container && \ 129 | echo "**** install apt-utils and locales ****" && \ 130 | apt-get update && \ 131 | apt-get install -y \ 132 | apt-utils \ 133 | locales && \ 134 | echo "**** install packages ****" && \ 135 | apt-get install -y \ 136 | curl \ 137 | gnupg \ 138 | jq \ 139 | netcat \ 140 | tzdata && \ 141 | echo "**** generate locale ****" && \ 142 | locale-gen en_US.UTF-8 && \ 143 | echo "**** create default user and make our folders ****" && \ 144 | useradd -u 911 -U -s /bin/false ${DEFAULT_USER} && \ 145 | usermod -G users ${DEFAULT_USER} && \ 146 | mkdir -p \ 147 | /app \ 148 | /config \ 149 | /home/${DEFAULT_USER} \ 150 | /defaults && \ 151 | chown -R ${DEFAULT_USER}:${DEFAULT_USER} /home/${DEFAULT_USER} && \ 152 | chmod +x /docker-mods && \ 153 | echo "**** cleanup ****" && \ 154 | apt-get autoremove && \ 155 | apt-get clean && \ 156 | rm -rf \ 157 | /tmp/* \ 158 | /var/lib/apt/lists/* \ 159 | /var/tmp/* \ 160 | /var/log/* 161 | 162 | 163 | COPY --from=rootfs-stage docker-baseimage-ubuntu/root/ / 164 | 165 | ENTRYPOINT ["/init"] 166 | 167 | 168 | FROM ubuntu_base as vscode_base 169 | # COPY OVER PROJECT FILES 170 | COPY --from=rootfs-stage BayesPBPKTutorial /home/${DEFAULT_USER}/BayesPBPK 171 | ENV DEFAULT_WORKSPACE=/home/${DEFAULT_USER}/BayesPBPK 172 | # set version label 173 | ARG BUILD_DATE 174 | ARG VERSION 175 | ARG CODE_RELEASE 176 | LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DATE}" 177 | LABEL maintainer="TimKnab" 178 | 179 | # environment settings 180 | ARG DEBIAN_FRONTEND="noninteractive" 181 | ENV HOME="/home/${DEFAULT_USER}" 182 | 183 | RUN \ 184 | echo "**** install runtime dependencies ****" && \ 185 | apt-get update && \ 186 | apt-get install -y \ 187 | git \ 188 | jq \ 189 | libatomic1 \ 190 | nano \ 191 | net-tools \ 192 | netcat \ 193 | sudo && \ 194 | echo "**** install code-server ****" && \ 195 | if [ -z ${CODE_RELEASE+x} ]; then \ 196 | CODE_RELEASE=$(curl -sX GET https://api.github.com/repos/coder/code-server/releases/latest \ 197 | | awk '/tag_name/{print $4;exit}' FS='[""]' | sed 's|^v||'); \ 198 | fi && \ 199 | mkdir -p /app/code-server && \ 200 | curl -o \ 201 | /tmp/code-server.tar.gz -L \ 202 | "https://github.com/coder/code-server/releases/download/v${CODE_RELEASE}/code-server-${CODE_RELEASE}-linux-amd64.tar.gz" && \ 203 | tar xf /tmp/code-server.tar.gz -C \ 204 | /app/code-server --strip-components=1 && \ 205 | echo "**** clean up ****" && \ 206 | apt-get clean && \ 207 | rm -rf \ 208 | /config/* \ 209 | /tmp/* \ 210 | /var/lib/apt/lists/* \ 211 | /var/tmp/* 212 | 213 | 214 | # add local files 215 | COPY --from=rootfs-stage docker-code-server/root / 216 | 217 | ## Install extensions 218 | RUN /app/code-server/bin/code-server --extensions-dir /config/extensions --install-extension julialang.language-julia 219 | RUN /app/code-server/bin/code-server --extensions-dir /config/extensions --install-extension synedra.auto-run-command 220 | RUN /app/code-server/bin/code-server --extensions-dir /config/extensions --install-extension Ikuyadeu.r 221 | 222 | 223 | # ports and volumes 224 | EXPOSE 8443 225 | RUN cp /init /init_lsio 226 | 227 | 228 | FROM vscode_base as rbase 229 | 230 | ENV R_VERSION=4.2.1 231 | ENV R_HOME=/usr/local/lib/R 232 | ENV TZ=Etc/UTC 233 | 234 | 235 | COPY --from=rootfs-stage rocker-versioned2/scripts/install_R_source.sh /rocker_scripts/install_R_source.sh 236 | RUN /rocker_scripts/install_R_source.sh 237 | 238 | 239 | 240 | ENV CRAN=https://packagemanager.rstudio.com/cran/__linux__/jammy/latest 241 | ENV LANG=en_US.UTF-8 242 | 243 | COPY --from=rootfs-stage rocker-versioned2/scripts /rocker_scripts 244 | 245 | RUN /rocker_scripts/setup_R.sh 246 | 247 | FROM rbase as rstudio 248 | ENV S6_VERSION=v2.1.0.2 249 | ENV RSTUDIO_VERSION=2022.07.2+576 250 | ARG DEFAULT_USER 251 | ENV DEFAULT_USER=bayes 252 | ENV PANDOC_VERSION=default 253 | ENV QUARTO_VERSION=default 254 | 255 | RUN /rocker_scripts/install_rstudio.sh && \ 256 | /rocker_scripts/install_pandoc.sh && \ 257 | /rocker_scripts/install_quarto.sh && \ 258 | /rocker_scripts/install_julia.sh && \ 259 | cp /init_lsio /init && \ 260 | echo "auth-minimum-user-id=911" >> /etc/rstudio/rserver.conf && \ 261 | rm -rf /home/${DEFAULT_USER}/R 262 | 263 | EXPOSE 8787 264 | 265 | 266 | 267 | ## Install R Packages 268 | 269 | RUN rm -rf /home/${DEFAULT_USER}/R && \ 270 | chown -R ${DEFAULT_USER}:${DEFAULT_USER} /home/${DEFAULT_USER} && \ 271 | R -e "install.packages('rstudioapi')" && \ 272 | R -e "install.packages('languageserver')" 273 | COPY .Rprofile /home/${DEFAULT_USER}/.Rprofile 274 | RUN chown ${DEFAULT_USER}:${DEFAULT_USER} /home/${DEFAULT_USER}/.Rprofile 275 | 276 | FROM rstudio as final 277 | COPY settings.json /config/data/Machine/settings.json 278 | COPY settings_user.json /config/data/User/settings.json 279 | 280 | WORKDIR /home/${DEFAULT_USER}/BayesPBPK/script 281 | RUN git clone https://github.com/metrumresearchgroup/Torsten && \ 282 | julia --project=/home/${DEFAULT_USER}/BayesPBPK -e 'import Pkg; Pkg.instantiate()' && \ 283 | chown -R ${DEFAULT_USER}:${DEFAULT_USER} /home/${DEFAULT_USER} && \ 284 | rm -rf /home/${DEFAULT_USER}/BayesPBPK/.Rproj.user && \ 285 | rm -rf /init_lsio && \ 286 | rm -rf /rocker_scripts && \ 287 | rm -rf /home/${DEFAULT_USER}/BayesPBPK/script/Torsten/.git && \ 288 | rm -rf /home/${DEFAULT_USER}/BayesPBPK/script/Torsten/example-models && \ 289 | rm -rf /home/${DEFAULT_USER}/BayesPBPK/script/Torsten/.gitignore && \ 290 | rm -rf /home/${DEFAULT_USER}/BayesPBPK/script/Torsten/.github 291 | 292 | ENV PASSWORD=metrumrg 293 | RUN sed -i 's|AUTH="password"|AUTH="none"|g' /etc/s6-overlay/s6-rc.d/svc-code-server/run 294 | RUN echo "script/Torsten/" >> /home/${DEFAULT_USER}/BayesPBPK/.gitignore 295 | ENV SUDO_PASSWORD='metrumrg' 296 | 297 | ## Install additional packages 298 | RUN apt update && \ 299 | apt install -y \ 300 | zlib1g-dev \ 301 | libxml2-dev \ 302 | libfontconfig1-dev \ 303 | ncdu \ 304 | pkg-config \ 305 | curl 306 | 307 | WORKDIR /home/${DEFAULT_USER}/BayesPBPK 308 | RUN R -e 'install.packages("renv"); install.packages("jsonlite"); renv::activate("/home/'${DEFAULT_USER}'/BayesPBPK"); renv::install("jsonlite"); renv::restore(); renv::install("languageserver")' 309 | RUN mkdir /data_store 310 | RUN chown -R ${DEFAULT_USER}:${DEFAULT_USER} /data_store 311 | # Run with docker run -it --rm -p 8443:8443 -p 8787:8787 bayespbpk:latest 312 | 313 | 314 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build-image: 2 | docker build . -t bayesianpbpk:latest --no-cache 3 | 4 | # Run with docker run -it --rm -p 8443:8443 -p 8787:8787 bayespbpk:latest 5 | -------------------------------------------------------------------------------- /Project.toml: -------------------------------------------------------------------------------- 1 | [deps] 2 | CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" 3 | Cairo = "159f3aea-2a34-519c-b102-8c37f9878175" 4 | CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597" 5 | Chain = "8be319e6-bccf-4806-a6f7-6fae938471bc" 6 | DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" 7 | DataFramesMeta = "1313f7d8-7da2-5740-9ea0-a2ca25f37964" 8 | DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def" 9 | Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" 10 | ExponentialAction = "e24c0720-ea99-47e8-929e-571b494574d3" 11 | ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18" 12 | Fontconfig = "186bb1d3-e1f7-5a2c-a377-96d770f13627" 13 | Gadfly = "c91e804a-d5a3-530f-b6f0-dfbca275c004" 14 | GlobalSensitivity = "af5da776-676b-467e-8baf-acd8249e4f0f" 15 | LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800" 16 | LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 17 | MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d" 18 | Optim = "429524aa-4258-5aef-a3af-852621145aeb" 19 | OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" 20 | Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" 21 | QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" 22 | StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" 23 | StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" 24 | Turing = "fce5fe82-541a-59a6-adf8-730c64b5f9a0" 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BayesPBPK-tutorial 2 | 3 | This tutorial demonstrates population Bayesian PBPK analyses using the open-source tools R/Stan/Torsten and Julia/SciML/Turing.jl. The examples herein can be run directly from this Github repository or by using a docker image. 4 | 5 | ## Setup 6 | 7 | ### 1. Github repository 8 | 9 | - Clone this Github repository by clicking the `code` drop-down menu on the repository page. 10 | - Copy the repository url. 11 | - Open a terminal, go to where you like the repository to be cloned and type `git clone `. 12 | - Set up the environment and install packages: 13 | - R: 14 | - Recommended IDE is Rstudio. 15 | - Activate the R project environment in Rstudio by going to `File` -> `Open Project` then browse to the `BayesPBPK.Rproj` file. 16 | - Activate the `renv` by running `library(renv)` and `renv::activate()` 17 | - Install/restore packages from the `renv.lock` file by running `renv::restore()` 18 | - This will install all packages listed in the `pkgs.R` file and will make them available for loading whenever this project environment is activated. 19 | - Clone the Torsten repository and place it under the `script` directory in the tutorial repository. 20 | - Torsten requires a C++ compiler. For further details on Torsten installation and required C++ compilers check out this [installation guide](https://metrumresearchgroup.github.io/Torsten/installation/). 21 | 22 | - Julia: 23 | - Recommended IDE is Visual Studio Code. 24 | - Open a julia REPL by going to `View` -> `Command Palette` then typing `Julia: Start REPL`. 25 | - Make sure you are in the root directory (where the `Project.toml` file is located) then activate the julia project environment by typing `]` -> `activate .` -> `instantiate`. This will install all packages listed in the `Project.toml` file and make them available for loading whenever this project environment is activated. 26 | 27 | ### 2. Docker image 28 | 29 | - Install and start [Docker desktop](https://www.docker.com/products/docker-desktop) 30 | - A Dockerfile and Makefile to build the docker image have been provided. From this directory run 31 | ``` 32 | make build-image 33 | ``` 34 | to build the image using the provided Dockerfile and add it to docker (Note: This may take up to an hour.) 35 | - A docker-compose file has been provided for convenience. After building the image, launch a docker container using the image via docker-compose. From this directory run: 36 | ``` 37 | docker-compose up -d 38 | ``` 39 | 40 | * This will launch the docker container, you can then access VSCode running in the docker container in a web browser by visiting: 41 | http://localhost:8443 42 | and RStudio by visiting: 43 | http://localhost:8787 44 | 45 | From RStudio and VSCode start the R and Julia projects as you normally would. All of the packages, binaries, and dependencies for R, Julia and STAN/Torsten should be pre-installed and the scripts should run with no additional configuration needed. 46 | 47 | 48 | ## Scripts to run the analyses 49 | 50 | - `script/mavoPBPKGenODE.R`: runs the R/Stan/Torsten general ODE analysis using the model `model/mavoPBPKGenODE.stan`. 51 | - `script/mavoPBPKLinODE.R`: runs the R/Stan/Torsten linear ODE analysis using the model `model/mavoPBPKLinODE.stan`. 52 | - `script/mavoPBPKGenODE_run.jl`: runs the Julia/SciML/Turing.jl general ODE analysis using the model `model/mavoPBPKGenODE.jl`. 53 | - `script/mavoPBPKLinODE_run.jl`: runs the Julia/SciML/Turing.jl linear ODE analysis using the model `model/mavoPBPKLinODE.jl`. **Note: This script is still not finalized and is kept in the repository as a place holder**. 54 | 55 | --- 56 | 57 | R `sessionInfo()` 58 | 59 | ``` 60 | R version 4.2.1 (2022-06-23) 61 | Platform: x86_64-apple-darwin17.0 (64-bit) 62 | Running under: macOS Big Sur ... 10.16 63 | 64 | Matrix products: default 65 | LAPACK: /Library/Frameworks/R.framework/Versions/4.2/Resources/lib/libRlapack.dylib 66 | 67 | locale: 68 | [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8 69 | 70 | attached base packages: 71 | [1] parallel stats graphics grDevices datasets utils methods base 72 | 73 | other attached packages: 74 | [1] here_1.0.1 cowplot_1.1.1 mrggsave_0.3.0 vpc_1.2.2 75 | [5] posterior_1.3.1 cmdstanr_0.5.3 future.apply_1.9.1 future_1.28.0 76 | [9] loo_2.5.1 bayesplot_1.9.0 rstan_2.26.13 StanHeaders_2.26.13 77 | [13] forcats_0.5.2 stringr_1.4.1 dplyr_1.0.10 purrr_0.3.5 78 | [17] readr_2.1.3 tidyr_1.2.1 tibble_3.1.8 ggplot2_3.3.6 79 | [21] tidyverse_1.3.2 renv_0.16.0 80 | 81 | loaded via a namespace (and not attached): 82 | [1] matrixStats_0.62.0 fs_1.5.2 bit64_4.0.5 lubridate_1.8.0 83 | [5] httr_1.4.4 rprojroot_2.0.3 tensorA_0.36.2 tools_4.2.1 84 | [9] backports_1.4.1 utf8_1.2.2 R6_2.5.1 DBI_1.1.3 85 | [13] colorspace_2.0-3 withr_2.5.0 tidyselect_1.2.0 gridExtra_2.3 86 | [17] prettyunits_1.1.1 processx_3.7.0 bit_4.0.4 curl_4.3.3 87 | [21] compiler_4.2.1 cli_3.4.1 rvest_1.0.3 xml2_1.3.3 88 | [25] labeling_0.4.2 scales_1.2.1 checkmate_2.1.0 ggridges_0.5.4 89 | [29] callr_3.7.2 digest_0.6.30 pkgconfig_2.0.3 parallelly_1.32.1 90 | [33] dbplyr_2.2.1 rlang_1.0.6 readxl_1.4.1 rstudioapi_0.14 91 | [37] generics_0.1.3 farver_2.1.1 jsonlite_1.8.3 vroom_1.6.0 92 | [41] googlesheets4_1.0.1 distributional_0.3.1 inline_0.3.19 magrittr_2.0.3 93 | [45] Rcpp_1.0.9 munsell_0.5.0 fansi_1.0.3 abind_1.4-5 94 | [49] lifecycle_1.0.3 yaml_2.3.6 stringi_1.7.8 plyr_1.8.7 95 | [53] pkgbuild_1.3.1 grid_4.2.1 listenv_0.8.0 crayon_1.5.2 96 | [57] haven_2.5.1 hms_1.1.2 knitr_1.40 ps_1.7.1 97 | [61] pillar_1.8.1 reshape2_1.4.4 codetools_0.2-18 stats4_4.2.1 98 | [65] reprex_2.0.2 glue_1.6.2 V8_4.2.1 data.table_1.14.4 99 | [69] RcppParallel_5.1.5 modelr_0.1.9 vctrs_0.4.2 tzdb_0.3.0 100 | [73] cellranger_1.1.0 gtable_0.3.1 assertthat_0.2.1 xfun_0.34 101 | [77] broom_1.0.1 googledrive_2.0.0 gargle_1.2.1 globals_0.16.1 102 | [81] ellipsis_0.3.2 103 | ``` 104 | 105 | --- 106 | 107 | Julia `versioninfo()` 108 | 109 | ``` 110 | Julia Version 1.8.2 111 | Commit 36034abf260 (2022-09-29 15:21 UTC) 112 | Platform Info: 113 | OS: macOS (x86_64-apple-darwin21.4.0) 114 | CPU: 12 × Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz 115 | WORD_SIZE: 64 116 | LIBM: libopenlibm 117 | LLVM: libLLVM-13.0.1 (ORCJIT, skylake) 118 | Threads: 4 on 6 virtual cores 119 | Environment: 120 | JULIA_EDITOR = code 121 | JULIA_NUM_THREADS = 4 122 | ``` 123 | 124 | Julia `Pkg.status()` 125 | 126 | ``` 127 | [336ed68f] CSV v0.10.6 128 | [159f3aea] Cairo v1.0.5 129 | [324d7699] CategoricalArrays v0.10.7 130 | [8be319e6] Chain v0.5.0 131 | [a93c6f00] DataFrames v1.4.1 132 | [1313f7d8] DataFramesMeta v0.12.0 133 | [459566f4] DiffEqCallbacks v2.24.3 134 | [31c24e10] Distributions v0.25.76 135 | [e24c0720] ExponentialAction v0.2.4 136 | [d4d017d3] ExponentialUtilities v1.21.1 137 | [186bb1d3] Fontconfig v0.4.0 138 | [c91e804a] Gadfly v1.3.4 139 | [af5da776] GlobalSensitivity v2.1.2 140 | [2ee39098] LabelledArrays v1.12.5 141 | [c7f686f2] MCMCChains v5.5.0 142 | [429524aa] Optim v1.7.3 143 | [1dea7af3] OrdinaryDiffEq v6.29.3 144 | [91a5bcdd] Plots v1.35.5 145 | [1fd47b50] QuadGK v2.6.0 146 | [2913bbd2] StatsBase v0.33.21 147 | [f3b207a7] StatsPlots v0.15.4 148 | [fce5fe82] Turing v0.21.12 149 | [37e2e46d] LinearAlgebra 150 | ``` 151 | -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKGenODE/mavoPBPKGenODE-MCMCDiagnostics-Corrs.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKGenODE/mavoPBPKGenODE-MCMCDiagnostics-Corrs.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKGenODE/mavoPBPKGenODE-MCMCDiagnostics.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKGenODE/mavoPBPKGenODE-MCMCDiagnostics.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKGenODE/mavoPBPKGenODE-PPC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKGenODE/mavoPBPKGenODE-PPC.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKGenODE_jl/DensPlots.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKGenODE_jl/DensPlots.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKGenODE_jl/MCMCTrace.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKGenODE_jl/MCMCTrace.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKGenODE_jl/PPCCond.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKGenODE_jl/PPCCond.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKGenODE_jl/PPCPred.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKGenODE_jl/PPCPred.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKGenODE_jl/PPCind.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKGenODE_jl/PPCind.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKGenODE_jl/SimPred.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKGenODE_jl/SimPred.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKGenODE_jl/sensitivity.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKGenODE_jl/sensitivity.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKLinODE/mavoPBPKLinODE-MCMCDiagnostics-Corrs.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKLinODE/mavoPBPKLinODE-MCMCDiagnostics-Corrs.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKLinODE/mavoPBPKLinODE-MCMCDiagnostics.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKLinODE/mavoPBPKLinODE-MCMCDiagnostics.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKLinODE/mavoPBPKLinODE-PPC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKLinODE/mavoPBPKLinODE-PPC.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKLinODE_jl/DensPlots.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKLinODE_jl/DensPlots.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKLinODE_jl/MCMCTrace.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKLinODE_jl/MCMCTrace.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKLinODE_jl/PPCCond.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKLinODE_jl/PPCCond.pdf -------------------------------------------------------------------------------- /deliv/figure/mavoPBPKLinODE_jl/PPCPred.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/deliv/figure/mavoPBPKLinODE_jl/PPCPred.pdf -------------------------------------------------------------------------------- /deliv/table/mavoPBPKGenODE/mavoPBPKGenODE-ParameterTable.csv: -------------------------------------------------------------------------------- 1 | variable,mean,median,sd,mad,q5,q95,rhat,ess_bulk,ess_tail 2 | CLintHat,1405.35493,1395.465,111.561799439096,99.4009170000001,1238.685,1604.3025,1.01081411729375,291.093512378378,327.178519125848 3 | KbBR,4.89158241,4.832675,0.841164511144818,0.789314001,3.641444,6.3619875,1.0063411613297,1318.6392959974,527.313200659033 4 | KbMU,1.75430343,1.749085,0.167505130899961,0.16404969,1.4861035,2.0418,1.00138715606044,1389.3573453697,822.386639033676 5 | KbAD,10.33134839,10.29645,0.653606803628495,0.617236032,9.3103285,11.50705,1.00328487510164,1395.73341143042,839.454011639855 6 | KbBO,1.061697843,1.03028,0.225624185450289,0.210343875,0.73891565,1.472335,1.00051124284056,1308.57094492144,685.062201693021 7 | KbRB,1.808155659,1.773395,0.375202359692825,0.344459871,1.256518,2.4588345,1.01029320764708,2054.43232142653,738.305694868035 8 | sigma,0.320770081,0.3205975,0.0143180660420192,0.0142188753,0.29768275,0.34459985,0.999809473514589,1568.19082235189,736.066739548065 9 | omega[1],0.364176574,0.3577955,0.0700632948901162,0.0690661797,0.26295945,0.4988838,1.02406507414188,195.065485263293,585.387389655453 10 | -------------------------------------------------------------------------------- /deliv/table/mavoPBPKGenODE_jl/Quantiles.csv: -------------------------------------------------------------------------------- 1 | parameters,2.5%,25.0%,50.0%,75.0%,97.5% 2 | σ,0.29280622346308155,0.3107737700829173,0.3202135343456193,0.33004015096418565,0.34966637188818167 3 | ĈLint,1190.5346011990946,1309.8325097040245,1390.5826157484003,1465.5258911804744,1628.533706360528 4 | KbBR,3.3297571327545357,4.342512371675038,4.900798906393177,5.544621867359902,6.8179866438391805 5 | KbMU,1.4276955656051729,1.635362268083389,1.7511688847004143,1.862438951315671,2.0916456029473887 6 | KbAD,9.255801296152958,9.89350737066249,10.299666945652955,10.728661299650307,11.66686510529657 7 | KbBO,0.6959760308367118,0.9114220289621162,1.0361724744004215,1.188907650818446,1.5350662371457233 8 | KbRB,1.1866918125792774,1.5536770914368656,1.7964542804976507,2.0250816507910274,2.551363888688878 9 | ω,0.2549031103970405,0.31324447692632706,0.3516078564989088,0.4011097390272162,0.5096991884330987 10 | ηᵢ[1],-2.1644883649562106,-1.6058947618582078,-1.3420741841631045,-1.0928247449935524,-0.5981876269393767 11 | ηᵢ[2],-1.4786256394977457,-0.9099368917118308,-0.6263221813995523,-0.33981588527048645,0.12647094448845772 12 | ηᵢ[3],-1.1069777093717095,-0.5406947725979991,-0.2694447851919677,-0.009371510899404918,0.5308536188497553 13 | ηᵢ[4],-0.9458768046889873,-0.4862046202473476,-0.2287207824933175,0.021713759371068134,0.4741104921992951 14 | ηᵢ[5],-2.6240044166478462,-1.9758122389368182,-1.688554319350451,-1.4025431496293017,-0.8891714003887992 15 | ηᵢ[6],-1.792158510315554,-1.2105153384395093,-0.9330506249409689,-0.6592220437003824,-0.17761177024720015 16 | ηᵢ[7],-1.5630561941363277,-1.041921858755778,-0.7863308344581765,-0.5270802281018465,-0.07459583785850556 17 | ηᵢ[8],-0.3068314793760953,0.2585496535522008,0.5040899915504805,0.7917103322565981,1.3464574248784011 18 | ηᵢ[9],-1.8250376675764959,-1.199500700279076,-0.9299320476426906,-0.6312131584933629,-0.13643611804403705 19 | ηᵢ[10],-0.1980391611828881,0.29058830965943766,0.5296266916262797,0.8125269413083137,1.3860632523695113 20 | ηᵢ[11],-1.249185954236972,-0.781172511262604,-0.5103107403868314,-0.2608320170004532,0.20458243219595698 21 | ηᵢ[12],-0.16053848035086066,0.3600543178259859,0.6128210955215305,0.8757313973511964,1.4762036520538153 22 | ηᵢ[13],0.1763056640795493,0.7037367317575471,1.0184214958072713,1.3400054936121988,1.9670192927593593 23 | ηᵢ[14],-0.2669600753894759,0.1579373122969719,0.41326805788715854,0.7133353751428404,1.192931885465565 24 | ηᵢ[15],-0.06632501138166144,0.48950072270712297,0.7678203704373383,1.045113464345471,1.5726467466276897 25 | ηᵢ[16],0.09268882720528396,0.5294337654871927,0.7744478453270708,1.0469755802576088,1.6608836086500676 26 | ηᵢ[17],-0.0424171100876957,0.34101467289009446,0.5759310910485006,0.8009621881679698,1.3238207194260145 27 | ηᵢ[18],-0.1362261260882084,0.38329885364932126,0.6512878827728057,0.9685498468851622,1.5549411589140731 28 | ηᵢ[19],0.07049704612493346,0.53345521171756,0.7757612282192909,1.016804951200958,1.4909998719970055 29 | ηᵢ[20],0.9001265154257877,1.4606936704515172,1.7342776954396657,2.083429584460882,2.7342435253078867 30 | -------------------------------------------------------------------------------- /deliv/table/mavoPBPKGenODE_jl/Summary.csv: -------------------------------------------------------------------------------- 1 | parameters,mean,std,naive_se,mcse,ess,rhat,ess_per_sec 2 | σ,0.32058770289516997,0.014581886936944125,0.00046111975303799526,0.0005032924637525625,1112.6767191871618,1.000205784992374,0.00603480843810223 3 | ĈLint,1391.555819254168,112.96631312519618,3.5723084834739383,6.1764727250015925,295.26749512932884,1.007348234067335,0.0016014379921649594 4 | KbBR,4.965151256496382,0.9149383429916613,0.028932890824740046,0.023856508645132942,1491.8386062182276,0.9986638975710892,0.008091263215850618 5 | KbMU,1.7517892728280038,0.1709341560684201,0.005405412630949001,0.004714802639014533,1194.1671593902934,0.9982102404700215,0.006476786946039181 6 | KbAD,10.343663653036405,0.6466028641218241,0.020447377922133345,0.017770380365716463,1045.6411641508137,0.9984398223502529,0.0056712286793006335 7 | KbBO,1.059877193676323,0.2135568567904059,0.006753260774040784,0.005813324846458732,1268.7453549513723,0.9974860341059583,0.00688127561387005 8 | KbRB,1.8082052585553061,0.3579814227400373,0.011320366558861126,0.010138934313603826,1334.649204134791,0.9982541683309288,0.007238717356199353 9 | ω,0.3605654216175772,0.065855167440339,0.0020825232480323206,0.004499746584046132,261.387550350405,1.0030379118149042,0.0014176838314922623 10 | ηᵢ[1],-1.353272385649556,0.40088432854248585,0.01267707556461504,0.01809456759184306,479.8095733326819,1.0016110760880315,0.002602336160988052 11 | ηᵢ[2],-0.6373897745815689,0.41584923054163553,0.013150307317400241,0.017509740584147306,692.7039584959545,1.0044813873051006,0.003757008322140543 12 | ηᵢ[3],-0.27911324340966326,0.40902874519161236,0.012934624632861403,0.01587178933142145,712.6665320279837,1.0022018462677103,0.0038652790400588014 13 | ηᵢ[4],-0.22990956873317173,0.35731683516745405,0.01129935045452107,0.01478589316572693,550.3498154279586,1.0029530723577071,0.0029849242397009166 14 | ηᵢ[5],-1.7049051812272928,0.44250893028280686,0.01399336104658327,0.02089594171605097,414.2815729077826,1.0053181495805101,0.0022469329040698755 15 | ηᵢ[6],-0.9379837847987428,0.41128127315881813,0.013005855821557393,0.01584073297426837,601.9911603113519,1.0015709123105525,0.003265010646186454 16 | ηᵢ[7],-0.7896045983704215,0.3821674036830639,0.012085194431115038,0.014503536421217492,542.7089203294877,1.002453145879549,0.0029434824287779813 17 | ηᵢ[8],0.5193293574140284,0.42046638124416447,0.013296314442602623,0.013552195240466334,611.9705675992452,1.000607872162343,0.0033191358114476022 18 | ηᵢ[9],-0.9246508823570057,0.42492312870445437,0.013437249171909492,0.015578496054019826,596.3955868226233,1.0005221960145698,0.0032346620161454935 19 | ηᵢ[10],0.5484910642500274,0.3981944253709641,0.012592013357541848,0.01361753312579198,774.982980257119,1.0025329675100523,0.004203263848333099 20 | ηᵢ[11],-0.5270167908119662,0.3730686357612579,0.0117974661257732,0.013321432441615797,696.3153726234399,1.0001953448594203,0.003776595496091618 21 | ηᵢ[12],0.6285881081292732,0.40987785450110115,0.012961475826865776,0.016207529235615786,635.9692359507152,1.0019631757229976,0.003449297037770795 22 | ηᵢ[13],1.021850230259032,0.47251179538608956,0.014942134947154833,0.016560919995308274,809.8438408672578,0.9994235967691266,0.004392338187844091 23 | ηᵢ[14],0.4324100984481774,0.3944682053449212,0.012474179934089571,0.011663454081743829,742.8715665448915,0.9979826826827518,0.00402910164372482 24 | ηᵢ[15],0.7721621549061682,0.41537625683572826,0.013135350575559866,0.017415822767467313,669.2565712049733,1.000926307789837,0.0036298370708372587 25 | ηᵢ[16],0.7992601411868739,0.39934593358779713,0.01262842724463776,0.01601475005030281,610.7955568779706,1.0020618253453015,0.003312762922994621 26 | ηᵢ[17],0.5909811297267387,0.3457351131718736,0.010933104247192023,0.015988765669711056,509.020955714044,1.0012796413415035,0.002760769508108369 27 | ηᵢ[18],0.6780795289451922,0.42868974985775077,0.013556360191183359,0.015457871608648224,741.6517513542843,1.0020310870457443,0.004022485749927222 28 | ηᵢ[19],0.7814127325551131,0.37599060205303225,0.011889866813055632,0.014497257267577814,702.1613428871616,1.0022055809959989,0.0038083021994566126 29 | ηᵢ[20],1.7808949970163555,0.47700478449001427,0.015084215737862044,0.02037422331147292,575.0008305842639,1.0012569166146705,0.003118623589842558 30 | -------------------------------------------------------------------------------- /deliv/table/mavoPBPKGenODE_jl/mavoPBPKGenODE_jl-ParameterTable.csv: -------------------------------------------------------------------------------- 1 | variable,mean,median,sd,mad,q5,q95,rhat,ess_bulk,ess_tail,ess_bulk_N,ess_tail_N 2 | σ,0.32058770289517,0.320213534345619,0.0145818869369441,0.0141646849566964,0.296506720969438,0.344619663125736,0.99994796133312,1084.00082446394,675.681652943958,1.08400082446394,0.675681652943958 3 | ĈLint,1391.55581925417,1390.5826157484,112.966313125196,116.931913193523,1216.12042477836,1585.22543113132,1.00445246491334,280.179981440284,527.471981695394,0.280179981440284,0.527471981695394 4 | KbBR,4.96515125649638,4.90079890639318,0.914938342991661,0.89229708018099,3.53615999351553,6.54156613676379,0.999010748406742,1382.40344931805,717.543294023979,1.38240344931805,0.717543294023979 5 | KbMU,1.751789272828,1.75116888470041,0.17093415606842,0.168044830736071,1.48809576504395,2.04137896474265,1.00853924769127,1058.88932776971,736.523837803121,1.05888932776971,0.736523837803121 6 | KbAD,10.3436636530364,10.299666945653,0.646602864121824,0.612278948434317,9.37321608540456,11.459543711344,0.999309545039112,1056.17824473815,772.648900938201,1.05617824473815,0.772648900938201 7 | KbBO,1.05987719367632,1.03617247440042,0.213556856790406,0.201831639695457,0.740767385004213,1.42372277300427,0.999198709467805,1350.50072151082,699.649956040612,1.35050072151082,0.699649956040612 8 | KbRB,1.80820525855531,1.79645428049765,0.357981422740037,0.351630162936348,1.25767828107182,2.42675560494726,0.99956739864982,1314.73486444328,875.763356197526,1.31473486444328,0.875763356197526 9 | ω,0.360565421617577,0.351607856498909,0.065855167440339,0.0632046802194232,0.269876905308073,0.48385483638062,1.00176515433007,267.508605512813,351.688298715419,0.267508605512813,0.351688298715419 10 | -------------------------------------------------------------------------------- /deliv/table/mavoPBPKLinODE/mavoPBPKLinODE-ParameterTable.csv: -------------------------------------------------------------------------------- 1 | variable,mean,median,sd,mad,q5,q95,rhat,ess_bulk,ess_tail 2 | CLintHat,1398.71158,1393.05,107.248659714302,107.295762,1229.766,1581.524,1.0157479683426,304.105714529728,533.291341481839 3 | KbBR,4.95213091,4.922875,0.848581606389022,0.84315462,3.6550735,6.35871,1.00269029411568,1287.93954063625,844.514628350521 4 | KbMU,1.7535953,1.750325,0.166624132879267,0.169112769,1.4849505,2.031401,1.00593829803006,1193.35833046463,752.244618368468 5 | KbAD,10.31225994,10.2675,0.726825732152981,0.751655961,9.2310325,11.534825,1.00026418554743,1331.04939537287,805.616633066814 6 | KbBO,1.052892488,1.03583,0.219995315693664,0.213094098,0.735494,1.468009,1.0051074382874,1317.86307860522,783.547536419081 7 | KbRB,1.785464926,1.767445,0.374576005633763,0.378174195,1.2279925,2.431186,1.00912804169227,1282.50622650233,737.221882918342 8 | sigma,0.320836897,0.3206005,0.0152126294950789,0.0159779802000001,0.2974618,0.3463832,1.01158477581555,963.497484714399,793.413186531461 9 | omega[1],0.35801792,0.3494465,0.0721201317605616,0.0681528981,0.2582893,0.4825288,1.02135932493967,197.356312570057,311.122236207308 10 | -------------------------------------------------------------------------------- /deliv/table/mavoPBPKLinODE_jl/Quantiles.csv: -------------------------------------------------------------------------------- 1 | parameters,2.5%,25.0%,50.0%,75.0%,97.5% 2 | σ,0.40414828763758226,0.4285100104380204,0.44275804380397,0.45702422907528784,0.4835131799684173 3 | ĈLint,1196.6570772188936,1343.154384715815,1426.8180041326777,1510.771601402384,1695.2680708204364 4 | KbBR,3.1883740945792773,4.255560445386967,4.933658779344274,5.628948869909907,7.182249668348981 5 | KbMU,1.376260272391851,1.6980316005531957,1.838040646661688,2.0125192065255133,2.3090662062047627 6 | KbAD,8.786788839956724,9.780217663194783,10.366076648544553,11.082079180825588,12.427982534247942 7 | KbBO,0.6947385339229494,0.9278396080377588,1.0906325686653886,1.2924045731306464,1.7461430099825925 8 | KbRB,1.147164213125915,1.550172661008666,1.7790342871016676,2.078315313132386,2.6382943089059303 9 | ω,0.22983062967323886,0.29703574692851037,0.3423597015132279,0.39490102479775424,0.5260828866691869 10 | ηᵢ[1],-2.3367324708599755,-1.7022945813925376,-1.3882447471631059,-1.0697714591050893,-0.5389350884100091 11 | ηᵢ[2],-1.7310954560003078,-0.9617501045470935,-0.5919486688709452,-0.25156148695332153,0.37746763037341835 12 | ηᵢ[3],-1.2617163276775238,-0.6222645024598418,-0.2943344098831644,0.06689317794433511,0.7755794014320347 13 | ηᵢ[4],-1.0729832130817398,-0.5323786306596072,-0.2366763841501631,0.04975754200364596,0.6465189292037817 14 | ηᵢ[5],-2.6608004013018953,-1.9507518151739245,-1.5790975094244066,-1.2399133171323284,-0.7463417504810258 15 | ηᵢ[6],-1.8877506422750776,-1.2229402069624875,-0.8655676618574335,-0.5179000231950769,0.09114269354417569 16 | ηᵢ[7],-1.7884766698005927,-1.061481713295279,-0.7306138104708289,-0.4199665480115408,0.1787163294775402 17 | ηᵢ[8],-0.6617680657360089,0.10017874223166945,0.48303211666091717,0.8743821381447263,1.6487117212993156 18 | ηᵢ[9],-1.8118240329242445,-1.1570144317321271,-0.8207843851042814,-0.5066165395780793,0.12156334718377979 19 | ηᵢ[10],-0.6101792357955657,0.12023990695336786,0.5117510307937856,0.831330175583274,1.516586340730576 20 | ηᵢ[11],-1.5183129524374528,-0.8066566168658963,-0.47656449626520436,-0.18828938826235797,0.41297115112005084 21 | ηᵢ[12],-0.5504011158114498,0.18191731688981608,0.5405142909909596,0.8980853861797357,1.6472015920300953 22 | ηᵢ[13],-0.07155296557119825,0.6073408184309002,0.9331624883671239,1.2985935298095002,2.024752389003562 23 | ηᵢ[14],-0.5561789484837181,0.03419405689075669,0.33946686115057,0.6978018505487285,1.3265920338748776 24 | ηᵢ[15],-0.18518921808542707,0.4290341020817886,0.7833932951138616,1.1876883933237787,1.8860699163815542 25 | ηᵢ[16],-0.2585557661641837,0.39653104311777154,0.7259019429524237,1.0519400805654557,1.7352603054396225 26 | ηᵢ[17],-0.276622184225724,0.2607356888752613,0.5521079469221488,0.8383474587001858,1.5737661713612618 27 | ηᵢ[18],-0.4470449471097504,0.2595148031064566,0.6116357370319001,0.9653514939330253,1.7708511249795844 28 | ηᵢ[19],-0.22994186047336654,0.3871127704487964,0.7208282104057422,1.0702197068529802,1.7958661487510972 29 | ηᵢ[20],0.5080834193564,1.1958576398336536,1.5799357000985803,1.9611166200631795,2.6857954109459254 30 | -------------------------------------------------------------------------------- /deliv/table/mavoPBPKLinODE_jl/Summary.csv: -------------------------------------------------------------------------------- 1 | parameters,mean,std,naive_se,mcse,ess,rhat,ess_per_sec 2 | σ,0.44290283446320095,0.020631973513571503,0.0006524402892715287,0.0007258548022617395,1157.2377419413224,0.9977073893670421,0.02592947810675907 3 | ĈLint,1430.310601235305,127.18234841805194,4.021858991701569,6.452538879865494,410.1857571269767,1.0068338920695103,0.009190767137689524 4 | KbBR,5.0011175415066775,1.028748606446275,0.03253188736094407,0.02777266781210242,1306.7946004235214,1.0003031142118062,0.02928050196917167 5 | KbMU,1.851437628432532,0.24257000964949527,0.007670737225414271,0.006410066016491418,1585.153677693993,0.9978155941489254,0.03551751389707016 6 | KbAD,10.455700981182444,0.953938558600394,0.0301661859303525,0.03264151492945957,1272.1083783608422,0.9994967985978893,0.02850331021074211 7 | KbBO,1.1303115477926347,0.27860502815872584,0.008810264565569211,0.005724920226010896,3094.7242567286157,0.9983516890574399,0.06934148615537435 8 | KbRB,1.8229682761356663,0.39284722942459216,0.012422920174684299,0.00984672859280729,1368.4039866152004,0.9991747095170914,0.03066094366453854 9 | ω,0.3514415778603489,0.07538354033247976,0.002383836855378028,0.0033005580916308907,418.60924537040313,0.997469074510747,0.009379506794265245 10 | ηᵢ[1],-1.397881002114083,0.46723722528371797,0.014775338395137616,0.016410522319832442,779.8320904208149,0.9987195706966967,0.01747319360807709 11 | ηᵢ[2],-0.6071818308663629,0.5268207431557849,0.01665953466994842,0.01731006693108123,1008.9176256300186,0.9989859255293804,0.02260616512680537 12 | ηᵢ[3],-0.28042562939094656,0.5100364170575464,0.016128767675334017,0.017312052549974474,1093.6517525342692,0.9993965317828033,0.02450474794071649 13 | ηᵢ[4],-0.23977022123519098,0.44027801977911535,0.013922813462106684,0.01544933073665392,858.6224594977471,1.0035223079678586,0.01923859848208039 14 | ηᵢ[5],-1.6104858879858712,0.5070829757364649,0.016035371660231272,0.01764930483537258,743.2423174838947,0.9972684732338157,0.016653350215562447 15 | ηᵢ[6],-0.8805021367869733,0.5116973259616114,0.01618129022656301,0.01381699123340388,1036.8822214805364,1.000217724749359,0.023232749751200665 16 | ηᵢ[7],-0.7469840585006616,0.4933721724023056,0.015601797989365531,0.0151597246055869,925.3895463052086,1.001823878341724,0.020734605441481768 17 | ηᵢ[8],0.4904030886301982,0.5751367513326614,0.018187421002810913,0.01601378891213778,1480.2488169645796,0.9987039960995254,0.033166978487628035 18 | ηᵢ[9],-0.8279444258146456,0.5068035597514081,0.01602653575095688,0.016152384856308905,932.8180520705623,1.0001989444415538,0.02090105116877506 19 | ηᵢ[10],0.48691467546553946,0.5252616695891142,0.016610232434844004,0.014588046457723844,1491.2700393767445,0.997975737019861,0.03341392389468549 20 | ηᵢ[11],-0.5030998422585514,0.4761454963677064,0.015057042661533822,0.01570368015189432,905.5402725077919,1.0016045617497242,0.020289855593017804 21 | ηᵢ[12],0.541494342280991,0.5445045911675674,0.017218747045083152,0.018220107382182816,1308.5239110743296,0.998618027070059,0.02931924951518991 22 | ηᵢ[13],0.9560477207561152,0.5211565932699419,0.01648041852346996,0.015234451044667308,1125.4011760929127,1.0009429581308378,0.025216136753256457 23 | ηᵢ[14],0.35705986335416856,0.48756548488828205,0.015418174407313778,0.01612574919586476,1086.8245768558568,1.001427656747703,0.024351775828013508 24 | ηᵢ[15],0.8120511516163752,0.5503658300049071,0.017404095691445458,0.014451555891507348,1288.6353818148584,0.9974861042961929,0.028873620094960334 25 | ηᵢ[16],0.7385160978408398,0.49410649050852723,0.015625019166793153,0.01492643844055116,1317.0674964229358,1.0018697174215785,0.029510680109977015 26 | ηᵢ[17],0.5615197817987009,0.45521559936649947,0.014395181204368404,0.019799653619100795,729.8071942177647,1.0041688637069897,0.016352318092287307 27 | ηᵢ[18],0.623702986333816,0.5480346833364471,0.017330378361122986,0.019236469635348568,1124.2870976806605,1.0005673869269969,0.025191174318354145 28 | ηᵢ[19],0.7341785557346155,0.5087862862212642,0.016089235067175387,0.016223212251377087,1417.7653467724663,0.9998122596721193,0.03176695175702484 29 | ηᵢ[20],1.5864684206917008,0.5462619605830799,0.017274319945516533,0.017694838221971147,1109.4322032957882,1.000887842694087,0.024858330301285876 30 | -------------------------------------------------------------------------------- /model/data.R: -------------------------------------------------------------------------------- 1 | addl <- 2 | c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 11 | amt <- 12 | c(25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13 | 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 14 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 15 | 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 16 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 17 | 0, 0, 0, 0, 0, 0, 0, 0, 37.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18 | 0, 0, 0, 0, 37.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19 | 37.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37.5, 0, 0, 20 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 21 | cmt <- 22 | c(15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 23 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 24 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 25 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 27 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 28 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 29 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 30 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 31 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 32 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 33 | 15, 15, 15, 15, 15) 34 | cObs <- 35 | c(491, 605, 556, 310, 237, 147, 101, 72.4, 52.6, 34.7, 34, 24.5, 14.1, 7.27, 3.95, 701, 459, 36 | 410, 303, 252, 199, 91.5, 64, 55.1, 49.1, 32.8, 15.6, 6.71, 303, 366, 374, 346, 303, 158, 84.7, 70.3, 37 | 51.5, 38, 36.2, 14, 4.91, 418, 337, 307, 211, 189, 107, 68.5, 38.4, 29.3, 26.6, 25, 16.5, 9.6, 3.91, 38 | 2.08, 736, 614, 445, 395, 359, 187, 93, 62, 52.5, 67.6, 54.2, 41.4, 14.2, 5.47, 250, 253, 374, 381, 390, 39 | 220, 195, 101, 68.3, 43.1, 38.8, 17.5, 5.19, 592, 569, 515, 411, 339, 231, 108, 80, 62, 38.8, 30.4, 40 | 19.3, 8.86, 2.84, 488, 587, 567, 433, 326, 165, 83.6, 59.8, 29.3, 31.5, 19.7, 5.75, 985, 755, 673, 507, 41 | 394, 175, 130, 74.8, 59, 49.6, 38.4, 19.6, 5.39, 269, 291, 265, 252, 244, 201, 97.5, 51.1, 34.7, 25.8, 42 | 18.3, 8.41, 3.81, 430, 433, 425, 413, 332, 198, 111, 77.9, 50.6, 28.6, 24, 14.8, 6.95, 4.13, 354, 312, 43 | 309, 340, 209, 171, 106, 55.9, 46.7, 25.7, 23.6, 12.7, 2.01, 381, 488, 355, 332, 293, 217, 80.5, 60.6, 44 | 44.6, 41, 36.3, 19, 4.78, 360, 311, 267, 226, 213, 129, 83.6, 48.8, 38.9, 41.1, 45.3, 19.3, 12.6, 5.19, 45 | 266, 351, 338, 279, 367, 170, 99.6, 64.3, 32.9, 25.3, 11.9, 4.16, 669, 446, 494, 363, 354, 159, 125, 46 | 74.3, 57.3, 23.8, 25, 12.5, 9.74, 2.62, 492, 410, 348, 289, 177, 105, 63.9, 44, 28.3, 25.2, 10.4, 9.4, 47 | 4.21, 2.11, 482, 436, 547, 486, 308, 286, 158, 94.5, 59.1, 28.6, 31.7, 11.5, 5.59, 550, 607, 471, 412, 48 | 292, 148, 69, 59.5, 38.4, 31.4, 41.9, 16.6, 9.7, 2.36, 535, 493, 378, 354, 176, 79, 50.9, 33.4, 21.6, 49 | 17, 13.2, 3.46) 50 | end <- 51 | c(16, 30, 44, 60, 75, 89, 104, 117, 131, 145, 160, 174, 188, 203, 216, 231, 246, 260, 275, 288) 52 | evid <- 53 | c(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 54 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 | 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 57 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58 | 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 59 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60 | 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 61 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 62 | ii <- 63 | c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 72 | iObs <- 73 | c(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 74 | 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 75 | 56, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81, 82, 83, 76 | 84, 85, 86, 87, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 106, 107, 108, 109, 77 | 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 78 | 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 147, 148, 149, 150, 151, 152, 153, 154, 79 | 155, 156, 157, 158, 159, 160, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 176, 177, 80 | 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 81 | 200, 201, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 218, 219, 220, 221, 222, 82 | 223, 224, 225, 226, 227, 228, 229, 230, 231, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 83 | 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 262, 263, 264, 265, 266, 267, 84 | 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288) 85 | nObs <- 268 86 | nSubject <- 20 87 | nt <- 288 88 | nti <- 89 | c(16, 14, 14, 16, 15, 14, 15, 13, 14, 14, 15, 14, 14, 15, 13, 15, 15, 14, 15, 13) 90 | rate <- 91 | c(75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92 | 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 93 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 94 | 0, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95 | 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 0, 96 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 97 | 0, 0, 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98 | 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 99 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 100 | ss <- 101 | c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 110 | start <- 111 | c(1, 17, 31, 45, 61, 76, 90, 105, 118, 132, 146, 161, 175, 189, 204, 217, 232, 247, 261, 276) 112 | time <- 113 | c(0, 0.2, 0.25, 0.367, 0.533, 0.7, 1.2, 2.2, 3.2, 4.2, 6.2, 8.2, 12.2, 24.2, 36.167, 48.167, 0, 114 | 0.2, 0.25, 0.367, 0.533, 0.7, 1.2, 2.2, 3.233, 4.2, 6.2, 8.25, 12.2, 24.2, 0, 0.2, 0.25, 0.367, 0.533, 115 | 0.7, 1.2, 2.2, 3.2, 4.2, 6.2, 8.2, 12.2, 24.2, 0, 0.2, 0.25, 0.367, 0.533, 0.7, 1.2, 2.2, 3.2, 4.2, 6.2, 116 | 8.267, 12.2, 24.2, 36.35, 48.167, 0, 0.233, 0.25, 0.367, 0.533, 0.7, 1.233, 2.2, 3.2, 4.2, 6.2, 8.2, 117 | 12.283, 24.2, 36.167, 0, 0.2, 0.25, 0.367, 0.533, 0.7, 1.2, 2.2, 3.2, 4.2, 6.2, 8.2, 12.233, 24.2, 0, 118 | 0.2, 0.25, 0.4, 0.533, 0.7, 1.2, 2.2, 3.2, 4.2, 6.2, 8.2, 12.2, 24.2, 36.167, 0, 0.2, 0.317, 0.417, 119 | 0.583, 0.7, 1.2, 2.417, 3.2, 4.2, 6.3, 8.35, 12.2, 0, 0.2, 0.25, 0.367, 0.533, 0.7, 1.2, 2.2, 3.2, 4.2, 120 | 6.2, 8.2, 12.2, 24.2, 0, 0.2, 0.25, 0.367, 0.533, 0.7, 1.2, 2.2, 3.2, 4.2, 6.2, 8.2, 12.2, 24.2, 0, 0.2, 121 | 0.25, 0.367, 0.533, 0.7, 1.2, 2.2, 3.2, 4.2, 6.2, 8.2, 12.2, 24.2, 36.167, 0, 0.2, 0.25, 0.367, 0.583, 122 | 0.733, 1.2, 2.2, 3.2, 4.2, 6.2, 8.2, 12.2, 24.2, 0, 0.25, 0.283, 0.367, 0.533, 0.7, 1.2, 2.2, 3.2, 4.2, 123 | 6.2, 8.2, 12.2, 24.2, 0, 0.2, 0.25, 0.367, 0.533, 0.7, 1.2, 2.2, 3.2, 4.2, 6.233, 8.283, 12.233, 24.2, 124 | 36.167, 0, 0.333, 0.417, 0.533, 0.7, 1.2, 2.2, 3.2, 4.2, 6.2, 8.25, 12.2, 24.2, 0, 0.2, 0.25, 0.367, 125 | 0.533, 0.7, 1.2, 2.2, 3.2, 4.2, 6.2, 8.2, 12.2, 24.2, 36.167, 0, 0.2, 0.333, 0.667, 0.7, 1.2, 2.2, 3.2, 126 | 4.2, 6.2, 8.2, 12.2, 24.2, 36.167, 48.167, 0, 0.2, 0.25, 0.367, 0.533, 0.7, 1.2, 2.2, 3.2, 4.2, 6.2, 127 | 8.2, 12.2, 24.2, 0, 0.233, 0.283, 0.367, 0.533, 0.7, 1.2, 2.2, 3.2, 4.2, 6.233, 8.2, 12.2, 24.2, 36.167, 128 | 0, 0.2, 0.367, 0.533, 0.7, 1.2, 2.25, 3.2, 4.2, 6.233, 8.2, 12.2, 24.2) 129 | weight <- 130 | c(94.3, 80.4, 71.8, 77.4, 64.3, 74.1, 87.9, 61.9, 65.3, 103.5, 83, 68.7, 64.4, 69.8, 86.1, 131 | 84.5, 99.1, 71.2, 82.6, 85.4) 132 | -------------------------------------------------------------------------------- /model/init.R: -------------------------------------------------------------------------------- 1 | CLintHat <- 1245.19123013436 2 | eta <- 3 | structure(c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 4 | .Dim = c(1, 20)) 5 | KbAD <- 6.86383556204729 6 | KbBO <- 1.36972329622999 7 | KbBR <- 2.62258481474506 8 | KbMU <- 1.11309219140056 9 | KbRB <- 2.3558411876281 10 | L <- 11 | structure(c(1), 12 | .Dim = c(1, 1)) 13 | omega <- 0.282161741678332 14 | sigma <- 0.674916845544405 15 | -------------------------------------------------------------------------------- /model/mavoPBPKGenODE.jl: -------------------------------------------------------------------------------- 1 | #= 2 | Version: October 7, 2022 3 | 4 | Online supplement to the tutorial: 5 | 6 | Bayesian PBPK Modeling using R/Stan/Torsten and Julia/SciML/Turing.jl 7 | 8 | This function defines the ODE function that would then be called by the ODEProblem function in script/mavoPBPKGenODE_run.jl 9 | 10 | For further details on how this function can be defined, checkout https://diffeq.sciml.ai/stable/ 11 | =# 12 | 13 | function PBPKODE!(du, u, p, t) 14 | ## parameters to be estimated ## 15 | CLint = p[1]; 16 | KbBR = p[2]; 17 | KbMU = p[3]; 18 | KbAD = p[4]; 19 | KbBO = p[5]; 20 | KbRB = p[6]; 21 | 22 | ## fixed parameters ## 23 | WT = p[7]; 24 | k₀ = p[8]; 25 | 26 | # Regional blood flows 27 | CO = (187.0*WT^0.81)*60/1000; # Cardiac output (L/h) from White et al (1968) 28 | QHT = 4.0 *CO/100; 29 | QBR = 12.0*CO/100; 30 | QMU = 17.0*CO/100; 31 | QAD = 5.0 *CO/100; 32 | QSK = 5.0 *CO/100; 33 | QSP = 3.0 *CO/100; 34 | QPA = 1.0 *CO/100; 35 | QLI = 25.5*CO/100; 36 | QST = 1.0 *CO/100; 37 | QGU = 14.0*CO/100; 38 | QHA = QLI - (QSP + QPA + QST + QGU); # Hepatic artery blood flow 39 | QBO = 5.0 *CO/100; 40 | QKI = 19.0*CO/100; 41 | QRB = CO - (QHT + QBR + QMU + QAD + QSK + QLI + QBO + QKI); 42 | QLU = QHT + QBR + QMU + QAD + QSK + QLI + QBO + QKI + QRB; 43 | 44 | # Organs' volumes = organs' weights / organs' density 45 | VLU = (0.76 *WT/100)/1.051; 46 | VHT = (0.47 *WT/100)/1.030; 47 | VBR = (2.00 *WT/100)/1.036; 48 | VMU = (40.0*WT/100)/1.041; 49 | VAD = (21.42*WT/100)/0.916; 50 | VSK = (3.71 *WT/100)/1.116; 51 | VSP = (0.26 *WT/100)/1.054; 52 | VPA = (0.14 *WT/100)/1.045; 53 | VLI = (2.57 *WT/100)/1.040; 54 | VST = (0.21 *WT/100)/1.050; 55 | VGU = (1.44 *WT/100)/1.043; 56 | VBO = (14.29*WT/100)/1.990; 57 | VKI = (0.44 *WT/100)/1.050; 58 | VAB = (2.81 *WT/100)/1.040; 59 | VVB = (5.62 *WT/100)/1.040; 60 | VRB = (3.86 *WT/100)/1.040; 61 | 62 | # partition coefficients 63 | KbLU = exp(0.8334); 64 | KbHT = exp(1.1205); 65 | KbSK = exp(-0.5238); 66 | KbSP = exp(0.3224); 67 | KbPA = exp(0.3224); 68 | KbLI = exp(1.7604); 69 | KbST = exp(0.3224); 70 | KbGU = exp(1.2026); 71 | KbKI = exp(1.3171); 72 | 73 | # Other parameters 74 | BP = 0.61; # Blood:plasma partition coefficient 75 | fup = 0.028; # Fraction unbound in plasma 76 | fub = fup/BP; # Fraction unbound in blood 77 | 78 | # model compartments 79 | Lungs = u[1]; 80 | Heart = u[2]; 81 | Brain = u[3]; 82 | Muscles = u[4]; 83 | Adipose = u[5]; 84 | Skin = u[6]; 85 | Spleen = u[7]; 86 | Pancreas = u[8]; 87 | Liver = u[9]; 88 | Stomach = u[10]; 89 | Gut = u[11]; 90 | Bones = u[12]; 91 | Kidneys = u[13]; 92 | Arterial_Blood = u[14]; 93 | Venous_Blood = u[15]; 94 | Rest_of_Body = u[16]; 95 | 96 | du[1] = dLungs = QLU*(Venous_Blood/VVB - Lungs/KbLU/VLU); #lungs 97 | du[2] = dHeart = QHT*(Arterial_Blood/VAB - Heart/KbHT/VHT); #heart 98 | du[3] = dBrain = QBR*(Arterial_Blood/VAB - Brain/KbBR/VBR); #brain 99 | du[4] = dMuscles = QMU*(Arterial_Blood/VAB - Muscles/KbMU/VMU); #muscles 100 | du[5] = dAdipose = QAD*(Arterial_Blood/VAB - Adipose/KbAD/VAD); #adipose 101 | du[6] = dSkin = QSK*(Arterial_Blood/VAB - Skin/KbSK/VSK); #skin 102 | du[7] = dSpleen = QSP*(Arterial_Blood/VAB - Spleen/KbSP/VSP); #spleen 103 | du[8] = dPancreas = QPA*(Arterial_Blood/VAB - Pancreas/KbPA/VPA); #pancreas 104 | du[9] = dLiver = QHA*Arterial_Blood/VAB + QSP*Spleen/KbSP/VSP + QPA*Pancreas/KbPA/VPA + QST*Stomach/KbST/VST + QGU*Gut/KbGU/VGU - CLint*fub*Liver/KbLI/VLI - QLI*Liver/KbLI/VLI; #liver 105 | du[10] = dStomach = QST*(Arterial_Blood/VAB - Stomach/KbST/VST); #stomach 106 | du[11] = dGut = QGU*(Arterial_Blood/VAB - Gut/KbGU/VGU); #gut 107 | du[12] = dBones = QBO*(Arterial_Blood/VAB - Bones/KbBO/VBO); #bones 108 | du[13] = dKidneys = QKI*(Arterial_Blood/VAB - Kidneys/KbKI/VKI); #kidneys 109 | du[14] = dArterial_Blood = QLU*(Lungs/KbLU/VLU - Arterial_Blood/VAB); #arterial blood 110 | du[15] = dVenous_Blood = k₀ + QHT*Heart/KbHT/VHT + QBR*Brain/KbBR/VBR + QMU*Muscles/KbMU/VMU + QAD*Adipose/KbAD/VAD + QSK*Skin/KbSK/VSK + QLI*Liver/KbLI/VLI + QBO*Bones/KbBO/VBO + QKI*Kidneys/KbKI/VKI + QRB*Rest_of_Body/KbRB/VRB - QLU*Venous_Blood/VVB; #venous_blood 111 | du[16] = dRest_of_Body = QRB*(Arterial_Blood/VAB - Rest_of_Body/KbRB/VRB); #rest of body 112 | end -------------------------------------------------------------------------------- /model/mavoPBPKGenODE.stan: -------------------------------------------------------------------------------- 1 | functions{ 2 | vector PBPKModelODE(real t, vector x, array[] real parms, array[] real rdummy, array[] int idummy){ 3 | vector[16] dxdt; 4 | real WT = rdummy[1]; 5 | 6 | //// fixed parameters //// 7 | // Regional blood flows 8 | real CO = (187.00*WT^0.81)*60/1000; // Cardiac output (L/h) from White et al (1968) 9 | real QHT = 4.0 *CO/100; 10 | real QBR = 12.0*CO/100; 11 | real QMU = 17.0*CO/100; 12 | real QAD = 5.0 *CO/100; 13 | real QSK = 5.0 *CO/100; 14 | real QSP = 3.0 *CO/100; 15 | real QPA = 1.0 *CO/100; 16 | real QLI = 25.5*CO/100; 17 | real QST = 1.0 *CO/100; 18 | real QGU = 14.0*CO/100; 19 | real QHA = QLI - (QSP + QPA + QST + QGU); // Hepatic artery blood flow 20 | real QBO = 5.0 *CO/100; 21 | real QKI = 19.0*CO/100; 22 | real QRB = CO - (QHT + QBR + QMU + QAD + QSK + QLI + QBO + QKI); 23 | real QLU = QHT + QBR + QMU + QAD + QSK + QLI + QBO + QKI + QRB; 24 | 25 | // Organs' volumes = organs' weights / organs' density 26 | real VLU = (0.76 *WT/100)/1.051; 27 | real VHT = (0.47 *WT/100)/1.030; 28 | real VBR = (2.00 *WT/100)/1.036; 29 | real VMU = (40.00*WT/100)/1.041; 30 | real VAD = (21.42*WT/100)/0.916; 31 | real VSK = (3.71 *WT/100)/1.116; 32 | real VSP = (0.26 *WT/100)/1.054; 33 | real VPA = (0.14 *WT/100)/1.045; 34 | real VLI = (2.57 *WT/100)/1.040; 35 | real VST = (0.21 *WT/100)/1.050; 36 | real VGU = (1.44 *WT/100)/1.043; 37 | real VBO = (14.29*WT/100)/1.990; 38 | real VKI = (0.44 *WT/100)/1.050; 39 | real VAB = (2.81 *WT/100)/1.040; 40 | real VVB = (5.62 *WT/100)/1.040; 41 | real VRB = (3.86 *WT/100)/1.040; 42 | 43 | // partition coefficients 44 | real KbLU = exp(0.8334); 45 | real KbHT = exp(1.1205); 46 | real KbSK = exp(-0.5238); 47 | real KbSP = exp(0.3224); 48 | real KbPA = exp(0.3224); 49 | real KbLI = exp(1.7604); 50 | real KbST = exp(0.3224); 51 | real KbGU = exp(1.2026); 52 | real KbKI = exp(1.3171); 53 | 54 | // Other parameters 55 | real BP = 0.61; // Blood:plasma partition coefficient 56 | real fup = 0.028; // Fraction unbound in plasma 57 | real fub = fup/BP; // Fraction unbound in blood 58 | 59 | //// parameters to be estimated //// 60 | real CLint = parms[1]; 61 | real KbBR = parms[2]; 62 | real KbMU = parms[3]; 63 | real KbAD = parms[4]; 64 | real KbBO = parms[5]; 65 | real KbRB = parms[6]; 66 | 67 | // model compartments 68 | real Lungs = x[1]; 69 | real Heart = x[2]; 70 | real Brain = x[3]; 71 | real Muscles = x[4]; 72 | real Adipose = x[5]; 73 | real Skin = x[6]; 74 | real Spleen = x[7]; 75 | real Pancreas = x[8]; 76 | real Liver = x[9]; 77 | real Stomach = x[10]; 78 | real Gut = x[11]; 79 | real Bones = x[12]; 80 | real Kidneys = x[13]; 81 | real Arterial_Blood = x[14]; 82 | real Venous_Blood = x[15]; 83 | real Rest_of_Body = x[16]; 84 | 85 | dxdt[1] = QLU*(Venous_Blood/VVB - Lungs/KbLU/VLU); //lungs 86 | dxdt[2] = QHT*(Arterial_Blood/VAB - Heart/KbHT/VHT); //heart 87 | dxdt[3] = QBR*(Arterial_Blood/VAB - Brain/KbBR/VBR); //brain 88 | dxdt[4] = QMU*(Arterial_Blood/VAB - Muscles/KbMU/VMU); //muscles 89 | dxdt[5] = QAD*(Arterial_Blood/VAB - Adipose/KbAD/VAD); //adipose 90 | dxdt[6] = QSK*(Arterial_Blood/VAB - Skin/KbSK/VSK); //skin 91 | dxdt[7] = QSP*(Arterial_Blood/VAB - Spleen/KbSP/VSP); //spleen 92 | dxdt[8] = QPA*(Arterial_Blood/VAB - Pancreas/KbPA/VPA); //pancreas 93 | dxdt[9] = QHA*Arterial_Blood/VAB + QSP*Spleen/KbSP/VSP + QPA*Pancreas/KbPA/VPA + QST*Stomach/KbST/VST + QGU*Gut/KbGU/VGU - CLint*fub*Liver/KbLI/VLI - QLI*Liver/KbLI/VLI; //liver 94 | dxdt[10] = QST*(Arterial_Blood/VAB - Stomach/KbST/VST); //stomach 95 | dxdt[11] = QGU*(Arterial_Blood/VAB - Gut/KbGU/VGU); //gut 96 | dxdt[12] = QBO*(Arterial_Blood/VAB - Bones/KbBO/VBO); //bones 97 | dxdt[13] = QKI*(Arterial_Blood/VAB - Kidneys/KbKI/VKI); //kidneys 98 | dxdt[14] = QLU*(Lungs/KbLU/VLU - Arterial_Blood/VAB); //arterial blood 99 | dxdt[15] = QHT*Heart/KbHT/VHT + QBR*Brain/KbBR/VBR + QMU*Muscles/KbMU/VMU + QAD*Adipose/KbAD/VAD + QSK*Skin/KbSK/VSK + QLI*Liver/KbLI/VLI + QBO*Bones/KbBO/VBO + QKI*Kidneys/KbKI/VKI + QRB*Rest_of_Body/KbRB/VRB - QLU*Venous_Blood/VVB; //venous_blood 100 | dxdt[16] = QRB*(Arterial_Blood/VAB - Rest_of_Body/KbRB/VRB); //rest of body 101 | 102 | return dxdt; 103 | } 104 | } 105 | 106 | data{ 107 | int nt; 108 | int nObs; 109 | array[nObs] int iObs; 110 | array[nt] real amt; 111 | array[nt] int cmt; 112 | array[nt] int evid; 113 | array[nt] real time; 114 | array[nt] real ii; 115 | array[nt] int addl; 116 | array[nt] int ss; 117 | array[nt] real rate; 118 | vector[nObs] cObs; 119 | 120 | // data for population model 121 | int nSubject; 122 | array[nSubject] int start; 123 | array[nSubject] int end; 124 | array[nSubject] real weight; 125 | } 126 | 127 | transformed data{ 128 | vector[nObs] logCObs = log(cObs); 129 | int nTheta = 6; // number of parameters 130 | int nIIV = 1; // parameters with IIV 131 | int nCmt = 16; // number of compartments 132 | array[nSubject, nCmt] real biovar; 133 | array[nSubject, nCmt] real tlag; 134 | array[nSubject] real VVB; 135 | array[nSubject] int len; 136 | array[nSubject, 1] real WT; 137 | array[nSubject, 1] int idummy; 138 | real BP = 0.61; // Blood:plasma partition coefficient 139 | 140 | for (i in 1:nSubject) { 141 | for (j in 1:nCmt) { 142 | biovar[i, j] = 1; 143 | tlag[i, j] = 0; 144 | } 145 | WT[i,1] = weight[i]; 146 | idummy[i, 1] = 0; 147 | len[i] = end[i] - start[i] + 1; 148 | VVB[i] = (5.62 * weight[i]/100) / 1.040; 149 | } 150 | } 151 | 152 | parameters{ 153 | real CLintHat; 154 | real KbBR; 155 | real KbMU; 156 | real KbAD; 157 | real KbBO; 158 | real KbRB; 159 | 160 | // residual error 161 | real sigma; 162 | 163 | // IIV parameters 164 | cholesky_factor_corr[nIIV] L; 165 | vector[nIIV] omega; 166 | matrix[nIIV, nSubject] etaStd; 167 | } 168 | 169 | transformed parameters{ 170 | row_vector[nt] cHat; 171 | row_vector[nObs] cHatObs; 172 | matrix[nCmt, nt] x; 173 | array[nSubject, nTheta] real parms; // The [1] indicates the parameters are constant 174 | 175 | // variables for Matt's trick 176 | vector[nIIV] thetaHat; 177 | matrix[nSubject, nIIV] thetaM; 178 | 179 | // Matt's trick to use unit scale 180 | thetaHat[1] = CLintHat; 181 | thetaM = (rep_matrix(thetaHat, nSubject) .* exp(diag_pre_multiply(omega, L * etaStd)))'; 182 | 183 | for(i in 1:nSubject) { 184 | parms[i, 1] = thetaM[i, 1]; // CLint 185 | parms[i, 2] = KbBR; 186 | parms[i, 3] = KbMU; 187 | parms[i, 4] = KbAD; 188 | parms[i, 5] = KbBO; 189 | parms[i, 6] = KbRB; 190 | } 191 | 192 | x = pmx_solve_group_rk45(PBPKModelODE, nCmt, len, 193 | time, amt, rate, ii, evid, cmt, addl, ss, 194 | parms, biovar, tlag, WT, idummy, 195 | 1e-6, 1e-6, 1e6); 196 | 197 | for(i in 1:nSubject) { 198 | cHat[start[i]:end[i]] = x[15, start[i]:end[i]] / (VVB[i]*BP/1000); // divide by subject's blood volume VVB 199 | } 200 | cHatObs = cHat[iObs]; 201 | } 202 | 203 | model{ 204 | // Priors 205 | CLintHat ~ lognormal(7.1, 0.25); 206 | KbBR ~ lognormal(1.1, 0.25); 207 | KbMU ~ lognormal(0.3, 0.25); 208 | KbAD ~ lognormal(2, 0.25); 209 | KbBO ~ lognormal(0.03, 0.25); 210 | KbRB ~ lognormal(0.3, 0.25); 211 | 212 | sigma ~ cauchy(0, 0.5); 213 | 214 | // Parameters for Matt's trick 215 | omega ~ cauchy(0, 0.5); 216 | L ~ lkj_corr_cholesky(1); 217 | to_vector(etaStd) ~ normal(0, 1); 218 | 219 | // observed data likelihood 220 | logCObs ~ normal(log(cHatObs), sigma); 221 | } 222 | 223 | generated quantities{ 224 | matrix[nCmt, nt] xPred; 225 | array[nSubject, nTheta] real parmsPred; 226 | row_vector[nt] cHatPred; 227 | row_vector[nObs] cHatObsPred; 228 | vector[nObs] cObsCond; 229 | row_vector[nObs] cObsPred; 230 | 231 | // Variables for IIV 232 | matrix[nIIV, nSubject] etaStdPred; 233 | matrix[nSubject, nIIV] thetaPredM; 234 | corr_matrix[nIIV] rho; 235 | 236 | rho = L * L'; 237 | for(i in 1:nSubject) { 238 | for(j in 1:nIIV) { 239 | etaStdPred[j, i] = normal_rng(0, 1); 240 | } 241 | } 242 | thetaPredM = (rep_matrix(thetaHat, nSubject) .* exp(diag_pre_multiply(omega, L * etaStdPred)))'; 243 | 244 | for(i in 1:nSubject) { 245 | parmsPred[i, 1] = thetaPredM[i, 1]; // CL 246 | parmsPred[i, 2] = KbBR; 247 | parmsPred[i, 3] = KbMU; 248 | parmsPred[i, 4] = KbAD; 249 | parmsPred[i, 5] = KbBO; 250 | parmsPred[i, 6] = KbRB; 251 | } 252 | 253 | xPred = pmx_solve_group_rk45(PBPKModelODE, nCmt, len, 254 | time, amt, rate, ii, evid, cmt, addl, ss, 255 | parmsPred, biovar, tlag, WT, idummy, 256 | 1e-6, 1e-6, 1e6); 257 | 258 | for(i in 1:nSubject) { 259 | cHatPred[start[i]:end[i]] = xPred[15, start[i]:end[i]] / (VVB[i]*BP/1000); 260 | } 261 | 262 | // predictions for observed data records 263 | cHatObsPred = cHatPred[iObs]; 264 | 265 | for(i in 1:nObs) { 266 | cObsCond[i] = exp(normal_rng(log(fmax(machine_precision(), cHatObs[i])), sigma)); // individual predictions 267 | cObsPred[i] = exp(normal_rng(log(fmax(machine_precision(), cHatObsPred[i])), sigma)); // population predictions 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /model/mavoPBPKGenODE/mavoPBPKGenODE.fit.RDS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/model/mavoPBPKGenODE/mavoPBPKGenODE.fit.RDS -------------------------------------------------------------------------------- /model/mavoPBPKGenODE_jl/mavoPBPKGenODEchains.jls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/model/mavoPBPKGenODE_jl/mavoPBPKGenODEchains.jls -------------------------------------------------------------------------------- /model/mavoPBPKGenODE_jl/mavoPBPKGenODEchains_prior.jls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/model/mavoPBPKGenODE_jl/mavoPBPKGenODEchains_prior.jls -------------------------------------------------------------------------------- /model/mavoPBPKLinODE.jl: -------------------------------------------------------------------------------- 1 | 2 | #function PBPK(p) 3 | function PBPK(p) 4 | ## parameters to be estimated ## 5 | CLint = p[1]; 6 | KbBR = p[2]; 7 | KbMU = p[3]; 8 | KbAD = p[4]; 9 | KbBO = p[5]; 10 | KbRB = p[6]; 11 | 12 | ## fixed parameters ## 13 | WT = p[7]; 14 | 15 | # Regional blood flows 16 | CO = (187.0*WT^0.81)*60/1000; # Cardiac output (L/h) from White et al (1968) 17 | QHT = 4.0 *CO/100; 18 | QBR = 12.0*CO/100; 19 | QMU = 17.0*CO/100; 20 | QAD = 5.0 *CO/100; 21 | QSK = 5.0 *CO/100; 22 | QSP = 3.0 *CO/100; 23 | QPA = 1.0 *CO/100; 24 | QLI = 25.5*CO/100; 25 | QST = 1.0 *CO/100; 26 | QGU = 14.0*CO/100; 27 | QHA = QLI - (QSP + QPA + QST + QGU); # Hepatic artery blood flow 28 | QBO = 5.0 *CO/100; 29 | QKI = 19.0*CO/100; 30 | QRB = CO - (QHT + QBR + QMU + QAD + QSK + QLI + QBO + QKI); 31 | QLU = QHT + QBR + QMU + QAD + QSK + QLI + QBO + QKI + QRB; 32 | 33 | # Organs' volumes = organs' weights / organs' density 34 | VLU = (0.76 *WT/100)/1.051; 35 | VHT = (0.47 *WT/100)/1.030; 36 | VBR = (2.00 *WT/100)/1.036; 37 | VMU = (40.0*WT/100)/1.041; 38 | VAD = (21.42*WT/100)/0.916; 39 | VSK = (3.71 *WT/100)/1.116; 40 | VSP = (0.26 *WT/100)/1.054; 41 | VPA = (0.14 *WT/100)/1.045; 42 | VLI = (2.57 *WT/100)/1.040; 43 | VST = (0.21 *WT/100)/1.050; 44 | VGU = (1.44 *WT/100)/1.043; 45 | VBO = (14.29*WT/100)/1.990; 46 | VKI = (0.44 *WT/100)/1.050; 47 | VAB = (2.81 *WT/100)/1.040; 48 | VVB = (5.62 *WT/100)/1.040; 49 | VRB = (3.86 *WT/100)/1.040; 50 | 51 | # partition coefficients 52 | KbLU = exp(0.8334); 53 | KbHT = exp(1.1205); 54 | KbSK = exp(-0.5238); 55 | KbSP = exp(0.3224); 56 | KbPA = exp(0.3224); 57 | KbLI = exp(1.7604); 58 | KbST = exp(0.3224); 59 | KbGU = exp(1.2026); 60 | KbKI = exp(1.3171); 61 | 62 | # Other parameters 63 | BP = 0.61; # Blood:plasma partition coefficient 64 | fup = 0.028; # Fraction unbound in plasma 65 | fub = fup/BP; # Fraction unbound in blood 66 | 67 | ncmt = 16; 68 | K = zeros(Base.promote_eltype(p[1]), ncmt, ncmt); 69 | 70 | K[1,1] = -QLU/KbLU/VLU; 71 | K[14,1] = QLU/KbLU/VLU; 72 | K[2,2] = -QHT/KbHT/VHT; 73 | K[15,2] = QHT/KbHT/VHT; 74 | K[3,3] = -QBR/KbBR/VBR; 75 | K[15,3] = QBR/KbBR/VBR; 76 | K[4,4] = -QMU/KbMU/VMU; 77 | K[15,4] = QMU/KbMU/VMU; 78 | K[5,5] = -QAD/KbAD/VAD; 79 | K[15,5] = QAD/KbAD/VAD; 80 | K[6,6] = -QSK/KbSK/VSK; 81 | K[15,6] = QSK/KbSK/VSK; 82 | K[7,7] = -QSP/KbSP/VSP; 83 | K[9,7] = QSP/KbSP/VSP; 84 | K[8,8] = -QPA/KbPA/VPA; 85 | K[9,8] = QPA/KbPA/VPA; 86 | K[9,9] = -(CLint*fub + QLI)/KbLI/VLI; 87 | K[15,9] = QLI/KbLI/VLI; 88 | K[9,10] = QST/KbST/VST; 89 | K[10,10] = -QST/KbST/VST; 90 | K[9,11] = QGU/KbGU/VGU; 91 | K[11,11] = -QGU/KbGU/VGU; 92 | K[12,12] = -QBO/KbBO/VBO; 93 | K[15,12] = QBO/KbBO/VBO; 94 | K[13,13] = -QKI/KbKI/VKI; 95 | K[15,13] = QKI/KbKI/VKI; 96 | K[2,14] = QHT/VAB; 97 | K[3,14] = QBR/VAB; 98 | K[4,14] = QMU/VAB; 99 | K[5,14] = QAD/VAB; 100 | K[6,14] = QSK/VAB; 101 | K[7,14] = QSP/VAB; 102 | K[8,14] = QPA/VAB; 103 | K[9,14] = QHA/VAB; 104 | K[10,14] = QST/VAB; 105 | K[11,14] = QGU/VAB; 106 | K[12,14] = QBO/VAB; 107 | K[13,14] = QKI/VAB; 108 | K[14,14] = -QLU/VAB; 109 | K[16,14] = QRB/VAB; 110 | K[1,15] = QLU/VVB; 111 | K[15,15] = -QLU/VVB; 112 | K[15,16] = QRB/KbRB/VRB; 113 | K[16,16] = -QRB/KbRB/VRB; 114 | 115 | return(K) 116 | end 117 | -------------------------------------------------------------------------------- /model/mavoPBPKLinODE.stan: -------------------------------------------------------------------------------- 1 | data{ 2 | int nt; 3 | int nObs; 4 | array[nObs] int iObs; 5 | array[nt] real amt; 6 | array[nt] int cmt; 7 | array[nt] int evid; 8 | array[nt] real time; 9 | array[nt] real ii; 10 | array[nt] int addl; 11 | array[nt] int ss; 12 | array[nt] real rate; 13 | vector[nObs] cObs; 14 | 15 | // data for population model 16 | int nSubject; 17 | array[nSubject] int start; 18 | array[nSubject] int end; 19 | array[nSubject] real weight; 20 | } 21 | 22 | transformed data{ 23 | vector[nObs] logCObs = log(cObs); 24 | int nTheta = 6; // number of parameters 25 | int nIIV = 1; // parameters with IIV 26 | int nCmt = 16; // number of compartments 27 | array[nCmt] real biovar; 28 | array[nCmt] real tlag; 29 | 30 | // objects to hold fixed parameters 31 | // Regional blood flows 32 | array[nSubject] real CO; // Cardiac output (L/h) from White et al (1968) 33 | array[nSubject] real QHT; 34 | array[nSubject] real QBR; 35 | array[nSubject] real QMU; 36 | array[nSubject] real QAD; 37 | array[nSubject] real QSK; 38 | array[nSubject] real QSP; 39 | array[nSubject] real QPA; 40 | array[nSubject] real QLI; 41 | array[nSubject] real QST; 42 | array[nSubject] real QGU; 43 | array[nSubject] real QHA; // Hepatic artery blood flow 44 | array[nSubject] real QBO; 45 | array[nSubject] real QKI; 46 | array[nSubject] real QRB; 47 | array[nSubject] real QLU; 48 | 49 | // Organs' volumes = organs' weights / organs' density 50 | array[nSubject] real VLU; 51 | array[nSubject] real VHT; 52 | array[nSubject] real VBR; 53 | array[nSubject] real VMU; 54 | array[nSubject] real VAD; 55 | array[nSubject] real VSK; 56 | array[nSubject] real VSP; 57 | array[nSubject] real VPA; 58 | array[nSubject] real VLI; 59 | array[nSubject] real VST; 60 | array[nSubject] real VGU; 61 | array[nSubject] real VBO; 62 | array[nSubject] real VKI; 63 | array[nSubject] real VAB; 64 | array[nSubject] real VVB; 65 | array[nSubject] real VRB; 66 | 67 | // partition coefficients 68 | real KbLU = exp(0.8334); 69 | real KbHT = exp(1.1205); 70 | real KbSK = exp(-0.5238); 71 | real KbSP = exp(0.3224); 72 | real KbPA = exp(0.3224); 73 | real KbLI = exp(1.7604); 74 | real KbST = exp(0.3224); 75 | real KbGU = exp(1.2026); 76 | real KbKI = exp(1.3171); 77 | 78 | // Other parameters 79 | real BP = 0.61; // Blood:plasma partition coefficient 80 | real fup = 0.028; // Fraction unbound in plasma 81 | real fub = fup/BP; // Fraction unbound in blood 82 | 83 | //// fixed parameters //// 84 | for(i in 1:nSubject) { 85 | // Regional blood flows 86 | CO[i] = (187.00*weight[i]^0.81)*60/1000; // Cardiac output (L/h) from White et al (1968) 87 | QHT[i] = 4.0*CO[i]/100; 88 | QBR[i] = 12.0*CO[i]/100; 89 | QMU[i] = 17.0*CO[i]/100; 90 | QAD[i] = 5.0 *CO[i]/100; 91 | QSK[i] = 5.0 *CO[i]/100; 92 | QSP[i] = 3.0 *CO[i]/100; 93 | QPA[i] = 1.0 *CO[i]/100; 94 | QLI[i] = 25.5*CO[i]/100; 95 | QST[i] = 1.0 *CO[i]/100; 96 | QGU[i] = 14.0*CO[i]/100; 97 | QHA[i] = QLI[i] - (QSP[i] + QPA[i] + QST[i] + QGU[i]); // Hepatic artery blood flow 98 | QBO[i] = 5.0 *CO[i]/100; 99 | QKI[i] = 19.0*CO[i]/100; 100 | QRB[i] = CO[i] - (QHT[i] + QBR[i] + QMU[i] + QAD[i] + QSK[i] + QLI[i] + QBO[i] + QKI[i]); 101 | QLU[i] = QHT[i] + QBR[i] + QMU[i] + QAD[i] + QSK[i] + QLI[i] + QBO[i] + QKI[i] + QRB[i]; 102 | 103 | // Organs' volumes = organs' weights / organs' density 104 | VLU[i] = (0.76 *weight[i]/100)/1.051; 105 | VHT[i] = (0.47 *weight[i]/100)/1.030; 106 | VBR[i] = (2.00 *weight[i]/100)/1.036; 107 | VMU[i] = (40.00*weight[i]/100)/1.041; 108 | VAD[i] = (21.42*weight[i]/100)/0.916; 109 | VSK[i] = (3.71 *weight[i]/100)/1.116; 110 | VSP[i] = (0.26 *weight[i]/100)/1.054; 111 | VPA[i] = (0.14 *weight[i]/100)/1.045; 112 | VLI[i] = (2.57 *weight[i]/100)/1.040; 113 | VST[i] = (0.21 *weight[i]/100)/1.050; 114 | VGU[i] = (1.44 *weight[i]/100)/1.043; 115 | VBO[i] = (14.29*weight[i]/100)/1.990; 116 | VKI[i] = (0.44 *weight[i]/100)/1.050; 117 | VAB[i] = (2.81 *weight[i]/100)/1.040; 118 | VVB[i] = (5.62 *weight[i]/100)/1.040; 119 | VRB[i] = (3.86 *weight[i]/100)/1.040; 120 | } 121 | 122 | for (i in 1:nCmt) { 123 | biovar[i] = 1; 124 | tlag[i] = 0; 125 | } 126 | } 127 | 128 | parameters{ 129 | real CLintHat; 130 | real KbBR; 131 | real KbMU; 132 | real KbAD; 133 | real KbBO; 134 | real KbRB; 135 | 136 | // residual error 137 | real sigma; 138 | 139 | // IIV parameters 140 | cholesky_factor_corr[nIIV] L; 141 | vector[nIIV] omega; 142 | matrix[nIIV, nSubject] etaStd; 143 | } 144 | 145 | transformed parameters{ 146 | row_vector[nt] cHat; 147 | row_vector[nObs] cHatObs; 148 | matrix[nCmt, nt] x; 149 | matrix[nCmt, nCmt] K; 150 | 151 | // variables for Matt's trick 152 | vector[nIIV] thetaHat; 153 | matrix[nSubject, nIIV] thetaM; 154 | 155 | // individual-level physiological paraeters 156 | array[nSubject] real CLint; 157 | 158 | // Matt's trick to use unit scale 159 | thetaHat[1] = CLintHat; 160 | thetaM = (rep_matrix(thetaHat, nSubject) .* exp(diag_pre_multiply(omega, L * etaStd)))'; 161 | 162 | for(i in 1:nSubject) { 163 | CLint[i] = thetaM[i, 1]; // CLint 164 | 165 | // Filling coefficient matrix 166 | K = rep_matrix(0, nCmt, nCmt); 167 | 168 | K[1,1] = -QLU[i]/KbLU/VLU[i]; 169 | K[14,1] = QLU[i]/KbLU/VLU[i]; 170 | K[2,2] = -QHT[i]/KbHT/VHT[i]; 171 | K[15,2] = QHT[i]/KbHT/VHT[i]; 172 | K[3,3] = -QBR[i]/KbBR/VBR[i]; 173 | K[15,3] = QBR[i]/KbBR/VBR[i]; 174 | K[4,4] = -QMU[i]/KbMU/VMU[i]; 175 | K[15,4] = QMU[i]/KbMU/VMU[i]; 176 | K[5,5] = -QAD[i]/KbAD/VAD[i]; 177 | K[15,5] = QAD[i]/KbAD/VAD[i]; 178 | K[6,6] = -QSK[i]/KbSK/VSK[i]; 179 | K[15,6] = QSK[i]/KbSK/VSK[i]; 180 | K[7,7] = -QSP[i]/KbSP/VSP[i]; 181 | K[9,7] = QSP[i]/KbSP/VSP[i]; 182 | K[8,8] = -QPA[i]/KbPA/VPA[i]; 183 | K[9,8] = QPA[i]/KbPA/VPA[i]; 184 | K[9,9] = -(CLint[i]*fub + QLI[i])/KbLI/VLI[i]; 185 | K[15,9] = QLI[i]/KbLI/VLI[i]; 186 | K[9,10] = QST[i]/KbST/VST[i]; 187 | K[10,10] = -QST[i]/KbST/VST[i]; 188 | K[9,11] = QGU[i]/KbGU/VGU[i]; 189 | K[11,11] = -QGU[i]/KbGU/VGU[i]; 190 | K[12,12] = -QBO[i]/KbBO/VBO[i]; 191 | K[15,12] = QBO[i]/KbBO/VBO[i]; 192 | K[13,13] = -QKI[i]/KbKI/VKI[i]; 193 | K[15,13] = QKI[i]/KbKI/VKI[i]; 194 | K[2,14] = QHT[i]/VAB[i]; 195 | K[3,14] = QBR[i]/VAB[i]; 196 | K[4,14] = QMU[i]/VAB[i]; 197 | K[5,14] = QAD[i]/VAB[i]; 198 | K[6,14] = QSK[i]/VAB[i]; 199 | K[7,14] = QSP[i]/VAB[i]; 200 | K[8,14] = QPA[i]/VAB[i]; 201 | K[9,14] = QHA[i]/VAB[i]; 202 | K[10,14] = QST[i]/VAB[i]; 203 | K[11,14] = QGU[i]/VAB[i]; 204 | K[12,14] = QBO[i]/VAB[i]; 205 | K[13,14] = QKI[i]/VAB[i]; 206 | K[14,14] = -QLU[i]/VAB[i]; 207 | K[16,14] = QRB[i]/VAB[i]; 208 | K[1,15] = QLU[i]/VVB[i]; 209 | K[15,15] = -QLU[i]/VVB[i]; 210 | K[15,16] = QRB[i]/KbRB/VRB[i]; 211 | K[16,16] = -QRB[i]/KbRB/VRB[i]; 212 | 213 | x[,start[i]:end[i]] = pmx_solve_linode(time[start[i]:end[i]], 214 | amt[start[i]:end[i]], 215 | rate[start[i]:end[i]], 216 | ii[start[i]:end[i]], 217 | evid[start[i]:end[i]], 218 | cmt[start[i]:end[i]], 219 | addl[start[i]:end[i]], 220 | ss[start[i]:end[i]], 221 | K, biovar, tlag); 222 | 223 | cHat[start[i]:end[i]] = x[15, start[i]:end[i]] / (VVB[i]*BP/1000); // divide by subject's blood volume VVB 224 | } 225 | cHatObs = cHat[iObs]; 226 | } 227 | 228 | model{ 229 | // Priors 230 | CLintHat ~ lognormal(7.1, 0.25); 231 | KbBR ~ lognormal(1.1, 0.25); 232 | KbMU ~ lognormal(0.3, 0.25); 233 | KbAD ~ lognormal(2, 0.25); 234 | KbBO ~ lognormal(0.03, 0.25); 235 | KbRB ~ lognormal(0.3, 0.25); 236 | 237 | sigma ~ cauchy(0, 0.5); 238 | 239 | // Parameters for Matt's trick 240 | omega ~ cauchy(0, 0.5); 241 | L ~ lkj_corr_cholesky(1); 242 | to_vector(etaStd) ~ normal(0, 1); 243 | 244 | // observed data likelihood 245 | logCObs ~ normal(log(cHatObs), sigma); 246 | } 247 | 248 | generated quantities{ 249 | matrix[nCmt, nt] xPred; 250 | matrix[nCmt, nCmt] KPred; 251 | row_vector[nt] cHatPred; 252 | row_vector[nObs] cHatObsPred; 253 | vector[nObs] cObsCond; 254 | row_vector[nObs] cObsPred; 255 | 256 | // Variables for IIV 257 | matrix[nIIV, nSubject] etaStdPred; 258 | matrix[nSubject, nIIV] thetaPredM; 259 | corr_matrix[nIIV] rho; 260 | 261 | // Individual-level model parameters 262 | array[nSubject] real CLintPred; 263 | 264 | rho = L * L'; 265 | for(i in 1:nSubject) { 266 | for(j in 1:nIIV) { 267 | etaStdPred[j, i] = normal_rng(0, 1); 268 | } 269 | } 270 | thetaPredM = (rep_matrix(thetaHat, nSubject) .* exp(diag_pre_multiply(omega, L * etaStdPred)))'; 271 | 272 | for(i in 1:nSubject) { 273 | CLintPred[i] = thetaPredM[i, 1]; // CLintPred 274 | 275 | // Filling coefficient matrix 276 | KPred = rep_matrix(0, nCmt, nCmt); 277 | 278 | KPred[1,1] = -QLU[i]/KbLU/VLU[i]; 279 | KPred[14,1] = QLU[i]/KbLU/VLU[i]; 280 | KPred[2,2] = -QHT[i]/KbHT/VHT[i]; 281 | KPred[15,2] = QHT[i]/KbHT/VHT[i]; 282 | KPred[3,3] = -QBR[i]/KbBR/VBR[i]; 283 | KPred[15,3] = QBR[i]/KbBR/VBR[i]; 284 | KPred[4,4] = -QMU[i]/KbMU/VMU[i]; 285 | KPred[15,4] = QMU[i]/KbMU/VMU[i]; 286 | KPred[5,5] = -QAD[i]/KbAD/VAD[i]; 287 | KPred[15,5] = QAD[i]/KbAD/VAD[i]; 288 | KPred[6,6] = -QSK[i]/KbSK/VSK[i]; 289 | KPred[15,6] = QSK[i]/KbSK/VSK[i]; 290 | KPred[7,7] = -QSP[i]/KbSP/VSP[i]; 291 | KPred[9,7] = QSP[i]/KbSP/VSP[i]; 292 | KPred[8,8] = -QPA[i]/KbPA/VPA[i]; 293 | KPred[9,8] = QPA[i]/KbPA/VPA[i]; 294 | KPred[9,9] = -(CLintPred[i]*fub + QLI[i])/KbLI/VLI[i]; 295 | KPred[15,9] = QLI[i]/KbLI/VLI[i]; 296 | KPred[9,10] = QST[i]/KbST/VST[i]; 297 | KPred[10,10] = -QST[i]/KbST/VST[i]; 298 | KPred[9,11] = QGU[i]/KbGU/VGU[i]; 299 | KPred[11,11] = -QGU[i]/KbGU/VGU[i]; 300 | KPred[12,12] = -QBO[i]/KbBO/VBO[i]; 301 | KPred[15,12] = QBO[i]/KbBO/VBO[i]; 302 | KPred[13,13] = -QKI[i]/KbKI/VKI[i]; 303 | KPred[15,13] = QKI[i]/KbKI/VKI[i]; 304 | KPred[2,14] = QHT[i]/VAB[i]; 305 | KPred[3,14] = QBR[i]/VAB[i]; 306 | KPred[4,14] = QMU[i]/VAB[i]; 307 | KPred[5,14] = QAD[i]/VAB[i]; 308 | KPred[6,14] = QSK[i]/VAB[i]; 309 | KPred[7,14] = QSP[i]/VAB[i]; 310 | KPred[8,14] = QPA[i]/VAB[i]; 311 | KPred[9,14] = QHA[i]/VAB[i]; 312 | KPred[10,14] = QST[i]/VAB[i]; 313 | KPred[11,14] = QGU[i]/VAB[i]; 314 | KPred[12,14] = QBO[i]/VAB[i]; 315 | KPred[13,14] = QKI[i]/VAB[i]; 316 | KPred[14,14] = -QLU[i]/VAB[i]; 317 | KPred[16,14] = QRB[i]/VAB[i]; 318 | KPred[1,15] = QLU[i]/VVB[i]; 319 | KPred[15,15] = -QLU[i]/VVB[i]; 320 | KPred[15,16] = QRB[i]/KbRB/VRB[i]; 321 | KPred[16,16] = -QRB[i]/KbRB/VRB[i]; 322 | 323 | xPred[,start[i]:end[i]] = pmx_solve_linode(time[start[i]:end[i]], 324 | amt[start[i]:end[i]], 325 | rate[start[i]:end[i]], 326 | ii[start[i]:end[i]], 327 | evid[start[i]:end[i]], 328 | cmt[start[i]:end[i]], 329 | addl[start[i]:end[i]], 330 | ss[start[i]:end[i]], 331 | KPred, biovar, tlag); 332 | 333 | cHatPred[start[i]:end[i]] = xPred[15, start[i]:end[i]] / (VVB[i]*BP/1000); 334 | } 335 | 336 | // predictions for observed data records 337 | cHatObsPred = cHatPred[iObs]; 338 | 339 | for(i in 1:nObs) { 340 | cObsCond[i] = exp(normal_rng(log(fmax(machine_precision(), cHatObs[i])), sigma)); // individual predictions 341 | cObsPred[i] = exp(normal_rng(log(fmax(machine_precision(), cHatObsPred[i])), sigma)); // population predictions 342 | } 343 | } 344 | -------------------------------------------------------------------------------- /model/mavoPBPKLinODE/mavoPBPKLinODE.fit.RDS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/model/mavoPBPKLinODE/mavoPBPKLinODE.fit.RDS -------------------------------------------------------------------------------- /model/mavoPBPKLinODE_jl/mavoPBPKLinODEchains.jls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/model/mavoPBPKLinODE_jl/mavoPBPKLinODEchains.jls -------------------------------------------------------------------------------- /model/mavoPBPKLinODE_jl/mavoPBPKLinODEchains_prior.jls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/model/mavoPBPKLinODE_jl/mavoPBPKLinODEchains_prior.jls -------------------------------------------------------------------------------- /model/naphPBPKGenODE.stan: -------------------------------------------------------------------------------- 1 | functions{ 2 | real[] PBPKModelODE(real t, real[] x, real[] parms, real[] rdummy, int[] idummy){ 3 | real dxdt[18]; 4 | real EXPO = rdummy[1]; 5 | 6 | // Skin exposure parameters. 7 | real AEXP = 20.0; // Area of exposed skin (cm^2). 8 | real VWELL = 1.0; // Volume of material in exposure well (mL). 9 | 10 | // Basic anatomical and physiological parameters. 11 | real BW = 63.5 * 1000; // Body mass (g). 12 | real QPUc = 1.2083; // Cardiac output (mL/min/g^0.75). 13 | 14 | // Skin parameters. 15 | //real DSC = 1.0e-8; // Fickian diffusion constant for stratum corneum (cm^2/min). 16 | real TSC = 0.003; // Thickness of stratum corneum (cm). 17 | real TVE = 0.0075; // Thickness of viable epidermis (cm). 18 | 19 | // Blood flows (as fractions of cardiac output) to ... 20 | real FBLI = 0.25; // ... liver. 21 | real FBFA = 0.07; // ... fat. 22 | real FBPP = 0.1675; // ... poorly perfused tissue. 23 | real FBRP = 0.5; // ... richly perfused tissue. 24 | 25 | // Volumes (as fractions of body mass) for ... 26 | real FTLI = 0.026; // ... liver. 27 | real FFAT = 0.136; // ... fat. 28 | real FTPP = 0.487; // ... poorly perfused tissue. 29 | real FTRP = 0.1861; // ... richly perfused tissue. 30 | real FTABD = 0.022; // ... arterial blood. 31 | real FTVBD = 0.045; // ... venous blood. 32 | real FTREM = 0.09; // ... remaining tissue. 33 | real FTPU = 0.0052; // ... pulmonary tissue 34 | 35 | // Partition coefficients for ... 36 | real HBA = 571.0; // ... blood:air. 37 | real HTB = 3.49; // ... general tissue:blood (incl. RP, PP, respiratory). 38 | real HLUB = 1.71; // ... lung:blood. 39 | real HLB = 1.61; // ... liver:blood. 40 | real HFB = 49.0; // ... fat:blood. 41 | real HRPB = 2.12; // ... richly perfused tissue:blood. 42 | real HPPB = 3.49; // ... poorly perfused tissue:blood. 43 | real HVEB = 2.73; // ... VE:blood (Eq. 23 of McCarley & Bunge, 2001) 44 | real HSCVE = 1.98; // ... SC:VE (Eq. 22 of McCarley & Bunge, 2001) 45 | //real HSCJP8 = 1.0; // ... SC:JP8. 46 | 47 | // Metabolism parameters. 48 | real VmaxLI = 100.8; // Vmax in liver (nmol/min/mL). 49 | real KmLI = 25.0; // Km in liver (nmol/mL). 50 | real VmaxLU = 0.27; // Vmax in lung (nmol/min/mL). 51 | real KmLU = 82.0; // Km in lung (nmol/mL). 52 | 53 | // Volumes (mL) of ... 54 | real VTLI = FTLI * BW; // ... liver tissue. 55 | real VFAT = FFAT * BW; // ... fat tissue. 56 | real VTSC = AEXP * TSC; // ... (exposed) stratum corneum. 57 | real VTVE = AEXP * TVE; // ... (exposed) viable epidermis. 58 | real VTRP = FTRP * BW - VTVE; // ... richly perfused tissue. 59 | real VTPP = FTPP * BW; // ... poorly perfused tissue. 60 | real VTAB = FTABD * BW; // ... arterial blood. 61 | real VTVB = FTVBD * BW; // ... venous blood. 62 | real VTREM = FTREM * BW; // ... remaining tissue. 63 | real VTPU = FTPU * BW; // ... pulmonary tissue 64 | 65 | // Discretization thickness for stratum corneum partial differential 66 | // equation discretization. 67 | real SCDX = TSC / 10; 68 | 69 | // Cardiac output (mL/min). 70 | real QPUa = QPUc * pow(BW, 0.75); 71 | 72 | // Blood flows (mL/min) to ... 73 | real QLI = FBLI * QPUa; // ... liver. 74 | real QVE = FBRP * (VTVE / VTRP) * QPUa; // ... viable epidermis. 75 | real QRP = FBRP * QPUa - QVE; // ... richly perfused tissue. 76 | real QPP = FBPP * QPUa; // ... poorly perfused tissue. 77 | real QFA = FBFA * QPUa; // ... fat tissue. 78 | 79 | // Total blood flow. COMPARE with QPUa. - DFK 2/15/2018 80 | real QPU = QLI + QVE + QRP + QPP + QFA; 81 | 82 | //// parameters to be estimated //// 83 | real HSCJP8 = parms[1]; 84 | real DSC = parms[2]*1e-8; 85 | 86 | // model compartments 87 | real APU = x[1]; 88 | real ALI = x[2]; 89 | real AFA = x[3]; 90 | real ARP = x[4]; 91 | real APP = x[5]; 92 | real AWELL = x[6]; 93 | real CSC01 = x[7]; 94 | real CSC02 = x[8]; 95 | real CSC03 = x[9]; 96 | real CSC04 = x[10]; 97 | real CSC05 = x[11]; 98 | real CSC06 = x[12]; 99 | real CSC07 = x[13]; 100 | real CSC08 = x[14]; 101 | real CSC09 = x[15]; 102 | real AVE = x[16]; 103 | real AAB = x[17]; 104 | real AVB = x[18]; 105 | 106 | // Naphthalene internal concentrations (nmol/mL) in ... 107 | real CPU = APU / VTPU; // ... pulmonary tissue. 108 | real CvPU = CPU / HLUB; // ... veins leaving pulmonary tissue. 109 | real CLI = ALI / VTLI; // ... liver tissue. 110 | real CvLI = CLI / HLB; // ... veins leaving liver tissue. 111 | real CFA = AFA / VFAT; // ... fat tissue. 112 | real CvFA = CFA / HFB; // ... veins leaving fat tissue. 113 | real CRP = ARP / VTRP; // ... richly perfused tissue. 114 | real CvRP = CRP / HRPB; // ... veins leaving richly perfused tissue. 115 | real CPP = APP / VTPP; // ... poorly perfused tissue. 116 | real CvPP = CPP / HPPB; // ... veins leaving poorly perfused tissue. 117 | real CAB = AAB / VTAB; // ... arterial blood. 118 | real CVB = AVB / VTVB; // ... venous blood. 119 | real CVE = VTVE > 0 ? AVE / VTVE : 0.0; // ... viable epidermis. 120 | real CvVE = CVE / HVEB; // ... veins leaving viable epidermis. 121 | real CWELL = (AWELL / VWELL) * EXPO; // ... skin exposure well. 122 | real CSC00 = (CWELL * HSCJP8) * EXPO + CSC01*(1 - EXPO); // ... outer surface of SC. 123 | real CSC10 = CVE * HSCVE; // ... interface of SC with VE. 124 | 125 | // ----- Metabolism ----- 126 | real RMLPU = VTPU * VmaxLU * CvPU / (KmLU + CvPU); // pulmonary tissue 127 | real RML = VTLI * VmaxLI * CvLI / (KmLI + CvLI); // Liver 128 | 129 | // ----- Fluxes ----- 130 | // Naphthalene fluxes (nmol/cm^2/min) at ... 131 | real JSC00 = -DSC * (CSC01 - CSC00) / SCDX; // ... outer surface of SC. 132 | real JSC10 = -DSC * (CSC10 - CSC09) / SCDX; // ... interface of SC with VE. 133 | 134 | // ----- Time rates of change of state variables (ODEs) in nmol/min ----- 135 | dxdt[1] = QPU * (CVB - CvPU) - RMLPU; // pulmonary tissue 136 | dxdt[2] = QLI * (CAB - CvLI) - RML; // liver tissue 137 | dxdt[3] = QFA * (CAB - CvFA); // fat tissue 138 | dxdt[4] = QRP * (CAB - CvRP); // richly perfused tissue 139 | dxdt[5] = QPP * (CAB - CvPP); // poorly perfused tissue 140 | dxdt[6] = -JSC00 * AEXP; // Dermal Exposure Well 141 | dxdt[7] = DSC * (CSC00 - 2 * CSC01 + CSC02) / (SCDX * SCDX); // Stratum Corneum 1 142 | dxdt[8] = DSC * (CSC01 - 2 * CSC02 + CSC03) / (SCDX * SCDX); // Stratum Corneum 2 CSC02 143 | dxdt[9] = DSC * (CSC02 - 2 * CSC03 + CSC04) / (SCDX * SCDX); // Stratum Corneum 3 144 | dxdt[10] = DSC * (CSC03 - 2 * CSC04 + CSC05) / (SCDX * SCDX); // Stratum Corneum 4 145 | dxdt[11] = DSC * (CSC04 - 2 * CSC05 + CSC06) / (SCDX * SCDX); // Stratum Corneum 5 146 | dxdt[12] = DSC * (CSC05 - 2 * CSC06 + CSC07) / (SCDX * SCDX); // Stratum Corneum 6 147 | dxdt[13] = DSC * (CSC06 - 2 * CSC07 + CSC08) / (SCDX * SCDX); // Stratum Corneum 7 148 | dxdt[14] = DSC * (CSC07 - 2 * CSC08 + CSC09) / (SCDX * SCDX); // Stratum Corneum 8 149 | dxdt[15] = DSC * (CSC08 - 2 * CSC09 + CSC10) / (SCDX * SCDX); // Stratum Corneum 9 150 | dxdt[16] = JSC10 * AEXP + QVE * (CAB - CvVE); // viable epidermis 151 | dxdt[17] = QPU * (CvPU - CAB); // arterial blood 152 | dxdt[18] = QLI * CvLI + QFA * CvFA + QRP * CvRP + QPP * CvPP + QVE * CvVE - QPU * CVB; // venous blood 153 | 154 | return dxdt; 155 | } 156 | } 157 | 158 | data{ 159 | int nt; 160 | int nObs; 161 | int iObs[nObs]; 162 | real amt[nt]; 163 | int cmt[nt]; 164 | int evid[nt]; 165 | real time[nt]; 166 | real ii[nt]; 167 | int addl[nt]; 168 | int ss[nt]; 169 | real rate[nt]; 170 | vector[nObs] cObs; 171 | real exposure[nt]; 172 | } 173 | 174 | transformed data{ 175 | vector[nObs] logCObs = log(cObs); 176 | int nTheta = 2; // number of parameters 177 | int nCmt = 18; // number of compartments 178 | real biovar[nCmt]; 179 | real tlag[nCmt]; 180 | real VTVB = 0.045 * 63.5 * 1000; // venous blood volume mL 181 | real EXPO[nt, 1]; 182 | int idummy[nt, 1]; 183 | 184 | for (i in 1:nCmt) { 185 | biovar[i] = 1; 186 | tlag[i] = 0; 187 | } 188 | 189 | for (i in 1:nt) { 190 | EXPO[i, 1] = exposure[i]; 191 | idummy[i, 1] = 0; 192 | } 193 | } 194 | 195 | parameters{ 196 | real HSCJP8; 197 | real NDSC; 198 | 199 | // residual error 200 | real sigma; 201 | } 202 | 203 | transformed parameters{ 204 | row_vector[nt] cHat; 205 | row_vector[nObs] cHatObs; 206 | matrix[nCmt, nt] x; 207 | real parms[nTheta]; 208 | 209 | parms[1] = HSCJP8; 210 | parms[2] = NDSC; 211 | 212 | x = pmx_solve_rk45(PBPKModelODE, nCmt, 213 | time, amt, rate, ii, evid, cmt, addl, ss, 214 | parms, biovar, tlag, EXPO, idummy, 215 | 1e-6, 1e-6, 1e6); 216 | 217 | cHat = x[18] / VTVB; // divide by subject's blood volume VTVB 218 | 219 | cHatObs = cHat[iObs]; 220 | } 221 | 222 | model{ 223 | // Priors 224 | HSCJP8 ~ lognormal(log(1.0), 0.25); 225 | NDSC ~ lognormal(log(1.0), 0.25); 226 | 227 | sigma ~ cauchy(0.0, 0.5); 228 | 229 | // observed data likelihood 230 | logCObs ~ normal(log(cHatObs), sigma); 231 | } 232 | 233 | generated quantities{ 234 | matrix[nCmt, nt] xPred; 235 | real parmsPred[nTheta]; 236 | row_vector[nt] cHatPred; 237 | row_vector[nObs] cHatObsPred; 238 | vector[nObs] cObsCond; 239 | row_vector[nObs] cObsPred; 240 | 241 | parmsPred[1] = HSCJP8; 242 | parmsPred[2] = NDSC; 243 | 244 | xPred = pmx_solve_rk45(PBPKModelODE, nCmt, 245 | time, amt, rate, ii, evid, cmt, addl, ss, 246 | parmsPred, biovar, tlag, EXPO, idummy, 247 | 1e-6, 1e-6, 1e6); 248 | 249 | cHatPred = xPred[18] / VTVB; 250 | 251 | // predictions for observed data records 252 | cHatObsPred = cHatPred[iObs]; 253 | 254 | for(i in 1:nObs) { 255 | cObsCond[i] = exp(normal_rng(log(fmax(machine_precision(), cHatObs[i])), sigma)); // individual predictions 256 | cObsPred[i] = exp(normal_rng(log(fmax(machine_precision(), cHatObsPred[i])), sigma)); // population predictions 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /pkgs.R: -------------------------------------------------------------------------------- 1 | renv::activate() 2 | options(repos = 3 | c(options()$repos,"https://metrumresearchgroup.github.io/r_validated","https://mc-stan.org/r-packages/")) 4 | renv::install(c("tidyverse", "mrgsolve", "rstan", "mrggsave", 5 | "bayesplot", "cowplot", "loo", "future.apply", 6 | "cmdstanr", "posterior", "vpc", "here")) 7 | renv::snapshot() 8 | -------------------------------------------------------------------------------- /renv/.gitignore: -------------------------------------------------------------------------------- 1 | library/ 2 | local/ 3 | cellar/ 4 | lock/ 5 | python/ 6 | sandbox/ 7 | staging/ 8 | -------------------------------------------------------------------------------- /script/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metrumresearchgroup/BayesPBPK-tutorial/439cf5da25b45b559abeed2d194c28b9985018ac/script/.keep -------------------------------------------------------------------------------- /script/getLinODEModel.R: -------------------------------------------------------------------------------- 1 | ## script to create mavoPBPK linear ODE model 2 | 3 | ## create coeff matrix 4 | 5 | getMatrix <- function(odes){ 6 | l <- unlist(strsplit(odes, ";")) 7 | cmts <- as.character(lapply(l, function(x) str_match(x, "dxdt_\\s*(.*?)\\s*=")[2])) 8 | ncmts <- length(cmts) 9 | K <- matrix("0", ncmts, ncmts) 10 | #Ks <- matrix("0", ncmts, ncmts) 11 | for(i in 1:ncmts){ 12 | cmt <- cmts[i] 13 | rhs <- gsub(".*=", "", l[i]) 14 | for(j in 1:ncmts){ 15 | lrhs <- unlist(strsplit(rhs, "\\([^)]*\\)(*SKIP)(*F)|(?<=.)(?=[-|\\+])", perl = TRUE)) 16 | for(k in 1:length(lrhs)){ 17 | if(grepl(cmts[j], lrhs[k])) K[i,j] <- lrhs[k] 18 | K[i,j] <- gsub(cmts[j], 1, K[i,j]) 19 | #K[i,j] <- str_replace_all(string=K[i,j], pattern=" ", repl="") 20 | } 21 | } 22 | } 23 | return(K) 24 | } 25 | 26 | m <- getMatrix(odes) 27 | df <- as_tibble(m) 28 | 29 | getMatrixText <- function(m){ 30 | ms <- m 31 | for(i in 1:nrow(m)){ 32 | for(j in 1:ncol(m)){ 33 | flux <- m[i,j] 34 | ms[i,j] <- sprintf("K[%s,%s] = %s;", i, j, flux) 35 | } 36 | } 37 | v <- c(ms) 38 | v2 <- v[!(grepl("= 0", v))] 39 | return(v2) 40 | } 41 | 42 | # get matrix text 43 | odes <- "dxdt_Lungs = QLU*Venous_Blood/VVB - QLU*Lungs/KbLU/VLU; 44 | dxdt_Heart = QHT*Arterial_Blood/VAB - QHT*Heart/KbHT/VHT; 45 | dxdt_Brain = QBR*Arterial_Blood/VAB - QBR*Brain/KbBR/VBR; 46 | dxdt_Muscles = QMU*Arterial_Blood/VAB - QMU*Muscles/KbMU/VMU; 47 | dxdt_Adipose = QAD*Arterial_Blood/VAB - QAD*Adipose/KbAD/VAD; 48 | dxdt_Skin = QSK*Arterial_Blood/VAB - QSK*Skin/KbSK/VSK; 49 | dxdt_Spleen = QSP*Arterial_Blood/VAB - QSP*Spleen/KbSP/VSP; 50 | dxdt_Pancreas = QPA*Arterial_Blood/VAB - QPA*Pancreas/KbPA/VPA; 51 | dxdt_Liver = QHA*Arterial_Blood/VAB + QSP*Spleen/KbSP/VSP + QPA*Pancreas/KbPA/VPA + QST*Stomach/KbST/VST + QGU*Gut/KbGU/VGU - (CLint*fub + QLI)*Liver/KbLI/VLI; 52 | dxdt_Stomach = QST*Arterial_Blood/VAB - QST*Stomach/KbST/VST; 53 | dxdt_Gut = QGU*Arterial_Blood/VAB - QGU*Gut/KbGU/VGU; 54 | dxdt_Bones = QBO*Arterial_Blood/VAB - QBO*Bones/KbBO/VBO; 55 | dxdt_Kidneys = QKI*Arterial_Blood/VAB - QKI*Kidneys/KbKI/VKI; 56 | dxdt_Arterial_Blood = QLU*Lungs/KbLU/VLU - QLU*Arterial_Blood/VAB; 57 | dxdt_Venous_Blood = QHT*Heart/KbHT/VHT + QBR*Brain/KbBR/VBR + QMU*Muscles/KbMU/VMU + QAD*Adipose/KbAD/VAD + QSK*Skin/KbSK/VSK + QLI*Liver/KbLI/VLI + QBO*Bones/KbBO/VBO + QKI*Kidneys/KbKI/VKI + QRB*Rest_of_Body/KbRB/VRB - QLU*Venous_Blood/VVB; 58 | dxdt_Rest_of_Body = QRB*Arterial_Blood/VAB - QRB*Rest_of_Body/KbRB/VRB;" 59 | 60 | K <- getMatrix(odes) 61 | Ks <- getMatrixText(K) 62 | 63 | ## update model file 64 | modelDir <- "../model" 65 | modelName <- "mavoPBPKLinODE" 66 | m_raw <- readLines(file.path(modelDir, paste0(modelName, "Raw.stan"))) 67 | m <- append(m_raw[1:166], Ks) 68 | m <- append(m, m_raw[167:230]) 69 | m <- append(m, Ks) 70 | m <- append(m, m_raw[231:length(m_raw)]) 71 | 72 | # save new model file 73 | write_lines(m, file = file.path(modelDir, paste0(modelName, ".stan"))) 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /script/mavoPBPKGenODE.R: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ################################## Intro ####################################### 3 | ################################################################################ 4 | 5 | # Version: October 20, 2022 6 | # 7 | # Online supplement to the tutorial: 8 | # 9 | # Bayesian PBPK Modeling using R/Stan/Torsten and Julia/SciML/Turing.jl 10 | # 11 | # This script runs the Bayesian PBPK modeling general ODE in R/Stan/Torsten 12 | 13 | ################################################################################ 14 | ################################## setup ####################################### 15 | ################################################################################ 16 | 17 | # clear working environment 18 | rm(list = ls()) 19 | gc() 20 | 21 | # load libraries 22 | library(tidyverse) 23 | library(rstan) 24 | library(bayesplot) 25 | library(loo) 26 | library(parallel) 27 | library(future.apply) 28 | library(cmdstanr) 29 | library(posterior) 30 | library(vpc) 31 | library(mrggsave) 32 | library(cowplot) 33 | library(here) 34 | 35 | # set environment 36 | setwd(here("script")) 37 | modelName <- "mavoPBPKGenODE" 38 | scriptName <- paste(modelName, "R", sep = ".") 39 | 40 | ## Relative paths assuming the working directory is the script directory 41 | ## containing this script 42 | scriptDir <- getwd() 43 | projectDir <- dirname(scriptDir) 44 | figDir <- file.path(projectDir, "deliv", "figure", modelName) 45 | tabDir <- file.path(projectDir, "deliv", "table", modelName) 46 | dataDir <- file.path(projectDir, "data") 47 | derivedDataDir <- file.path(dataDir, "derived") 48 | sourceDataDir <- file.path(dataDir, "source") 49 | modelDir <- file.path(projectDir, "model") 50 | ## Path for cmdstan interface to Stan 51 | stanDir <- file.path(scriptDir, "Torsten", "cmdstan") 52 | outDir <- file.path(modelDir, modelName) 53 | toolsDir <- file.path(scriptDir, "tools") 54 | tempDir <- file.path(scriptDir, "temp") 55 | invisible(dir.create(tempDir,recursive=T)) 56 | invisible(dir.create(figDir,recursive=T)) 57 | invisible(dir.create(tabDir,recursive=T)) 58 | invisible(dir.create(outDir,recursive=T)) 59 | 60 | # other conditions 61 | # caution: if fitModel = TRUE, this will fit and overwrite the already saved fit object 62 | # if you only want to run the analysis on the already saved fit object, set fitModel <- FALSE and runAnalysis <- TRUE 63 | fitModel <- TRUE 64 | useRStan <- FALSE 65 | runAnalysis <- FALSE 66 | nslaves <- 4 67 | 68 | source(file.path(toolsDir, "stanTools.R")) 69 | source(file.path(toolsDir, "functions.R")) 70 | if(!useRStan) source(file.path(toolsDir, "cmdStanTools.R")) 71 | set_cmdstan_path(stanDir) 72 | 73 | rstan_options(auto_write = TRUE) 74 | options(mc.cores = parallel::detectCores()) 75 | 76 | set.seed(123) ## not required but assures repeatable results 77 | 78 | ################################################################################ 79 | ################################# Prepare data ################################# 80 | ################################################################################ 81 | 82 | ## load mavoglurant data 83 | dat <- read.csv(file.path(dataDir, "Mavoglurant_A2121_nmpk.csv")) %>% 84 | # 15 is venous blood compartment ; intravenous administration ; for evid=0 it won't matter but needs to be > 0 85 | mutate(CMT = 15, 86 | excl = ifelse(DV <= 0 & EVID == 0, 1, 0)) %>% 87 | # grab the first 20 subjects 88 | filter(ID <= 812, 89 | excl == 0) %>% 90 | select(-excl) 91 | 92 | ## explore observed data 93 | ggplot(data=dat %>% filter(EVID == 0), aes(x=TIME, y=DV, col=factor(ID))) + 94 | geom_line() + 95 | theme_bw() + 96 | theme(legend.position = "none") + 97 | scale_y_continuous(trans = "log10") 98 | 99 | ## prepare input data 100 | nt <- nrow(dat) 101 | start <- (1:nt)[!duplicated(dat$ID)] 102 | end <- c(start[-1] - 1, nt) 103 | nti <- end - start + 1 104 | nSubject <- length(unique(dat$ID)) 105 | weights <- dat %>% group_by(ID) %>% slice(1) %>% pull(WT) 106 | ii <- rep(0, nt) 107 | addl <- rep(0, nt) 108 | ss <- rep(0, nt) 109 | 110 | ## Indices of records containing observed concentrations 111 | iObs <- with(dat, (1:nrow(dat))[EVID == 0]) 112 | nObs <- length(iObs) 113 | 114 | ## create data set 115 | data <- with(dat, 116 | list( 117 | nSubject = nSubject, 118 | nt = nt, 119 | nObs = nObs, 120 | iObs = iObs, 121 | time = TIME, 122 | amt = AMT, 123 | rate = RATE, 124 | cmt = CMT, 125 | evid = EVID, 126 | ii = ii, 127 | addl = addl, 128 | ss = ss, 129 | start = start, 130 | end = end, 131 | nti = nti, 132 | weight = weights, 133 | cObs = DV[iObs] 134 | )) 135 | 136 | nIIV <- 1 137 | nTheta <- 6 138 | 139 | ## get inits 140 | init <- function(){ 141 | list(CLintHat = rlnorm(1, meanlog=7.1, sdlog=0.25), 142 | KbBR = rlnorm(1, meanlog=1.1, sdlog=0.25), 143 | KbMU = rlnorm(1, meanlog=0.3, sdlog=0.25), 144 | KbAD = rlnorm(1, meanlog=2, sdlog=0.25), 145 | KbBO = rlnorm(1, meanlog=0.03, sdlog=0.25), 146 | KbRB = rlnorm(1, meanlog=0.3, sdlog=0.25), 147 | #omega = exp(rnorm(nIIV, log(0.05), 0.5)), 148 | omega = exp(rnorm(nIIV, log(0.25), 0.25)), 149 | L = diag(nIIV), 150 | sigma = runif(1, 0.25, 1), 151 | etaStd = matrix(rep(0, nIIV * nSubject), nrow = nIIV)) 152 | } 153 | 154 | ################################################################################ 155 | ################################################################################ 156 | 157 | ################################################################################ 158 | ################################# Run model #################################### 159 | ################################################################################ 160 | 161 | ## The Stan model 162 | modelFile <- file.path(modelDir, paste(modelName, ".stan", sep = "")) 163 | 164 | ## Run Stan 165 | nChains <- 4 166 | nPost <- 250 ## Number of post-burn-in samples per chain after thinning 167 | nBurn <- 250 ## Number of burn-in samples per chain after thinning 168 | nThin <- 1 169 | 170 | nIter <- (nPost + nBurn) * nThin 171 | nBurnin <- nBurn * nThin 172 | 173 | if(fitModel){ 174 | # create stan model object 175 | file.copy(file.path(modelDir, paste0(modelName, ".stan")), 176 | file.path(outDir, paste0(modelName, ".stan")), overwrite = TRUE) 177 | 178 | mod <- cmdstan_model(file.path(outDir, paste0(modelName, ".stan"))) 179 | 180 | fit <- mod$sample(data = data, chains = nChains, init = init, 181 | parallel_chains = nChains, 182 | iter_warmup = nBurn, iter_sampling = nPost, 183 | seed = sample(1:999999, 1), adapt_delta = 0.8, 184 | refresh = 10, 185 | output_dir = outDir) 186 | 187 | ## uncomment the following lines to run MPI 188 | # metworx 189 | #mod <- cmdstan_model(file.path(outDir, paste0(modelName, ".stan")), 190 | # cpp_options=list(TORSTEN_MPI=1,TBB_CXX_TYPE="gcc"),force_recompile=TRUE,quiet=FALSE) 191 | 192 | # local 193 | ## uncomment the following lines to run MPI locally 194 | # mod <- cmdstan_model(file.path(outDir, paste0(modelName, ".stan")), 195 | # cpp_options=list(TORSTEN_MPI=1,TBB_CXX_TYPE="clang"),force_recompile=TRUE,quiet=FALSE) 196 | # 197 | 198 | # fit <- mod$sample_mpi(data = data, chains = nChains, init = init, 199 | # #parallel_chains = nChains, 200 | # iter_warmup = nBurn, iter_sampling = nPost, 201 | # seed = sample(1:999999, 1), adapt_delta = 0.8, 202 | # refresh = 10, 203 | # # the -l option will tag each output line with MPI process id 204 | # mpi_args = list("n" = nslaves, "-l" = NULL), 205 | # output_dir = outDir) 206 | 207 | 208 | fit$save_object(file.path(outDir, paste0(modelName, ".fit.RDS"))) 209 | }else{ 210 | fit <- readRDS(file.path(outDir, paste0(modelName, ".fit.RDS"))) 211 | } 212 | 213 | ################################################################################ 214 | ################################################################################ 215 | 216 | ################################################################################ 217 | ################################## Analysis #################################### 218 | ################################################################################ 219 | 220 | if(runAnalysis){ 221 | 222 | # load fit object 223 | fit <- readRDS(file.path(outDir, paste0(modelName, ".fit.RDS"))) 224 | 225 | ## Specify the variables for which you want history and density plots 226 | parametersToPlot <- c("CLintHat", "KbBR", "KbMU", "KbAD", "KbBO", "KbRB", 227 | "sigma", "omega", "rho") 228 | 229 | ## Additional variables to monitor 230 | otherRVs <- c("cObsCond", "cObsPred", 231 | "cHat") 232 | 233 | parameters <- c(parametersToPlot, otherRVs) 234 | 235 | # set theme for plots 236 | myTheme <- theme(text = element_text(size = 12), axis.text = element_text(size = 12)) 237 | 238 | parametersToPlot <- setdiff(parametersToPlot, "rho") 239 | subset.pars <- subset_draws(fit$draws(), variable=parametersToPlot) 240 | 241 | ## diagnostics ## 242 | # summary 243 | # fitSumm <- fit$summary() # this will grab all model outputs 244 | fitSummParams <- fit$summary(variables = parametersToPlot) 245 | write.csv(fitSummParams, file = file.path(tabDir, paste(modelName, "ParameterTable.csv", sep = "-")), quote = F, row.names = F) 246 | 247 | # density 248 | plot_mcmcDensityByChain <- mcmc_dens_overlay(subset.pars, facet_args=list(ncol=2))+facet_text(size=10)+theme(axis.text=element_text(size=10)) 249 | plot_mcmcDensity <- mcmc_dens(subset.pars, facet_args=list(ncol=4))+facet_text(size=10)+theme(axis.text=element_text(size=10)) 250 | 251 | # rhat 252 | rhats <- bayesplot::rhat(fit, pars = parametersToPlot) 253 | plot_rhat <- mcmc_rhat(rhats) + yaxis_text() + myTheme 254 | 255 | # neff 256 | ratios1 <- bayesplot::neff_ratio(fit, pars = parametersToPlot) 257 | plot_neff <- mcmc_neff(ratios1) + yaxis_text() + myTheme 258 | 259 | # history 260 | draws_array <- fit$draws() 261 | plot_mcmcHistory <- mcmc_trace(draws_array, pars = c(parametersToPlot[1:7], "omega[1]"), facet_args = list(ncol = 2)) 262 | 263 | # correlation 264 | plot_pairs <- mcmc_pairs(draws_array, pars = c(parametersToPlot[1:7], "omega[1]"), off_diag_args = list(size = 1.5), diag_fun = "dens") 265 | 266 | # join history and densities 267 | plot_historyDensity <- plot_grid(plot_mcmcHistory, plot_mcmcDensityByChain, ncol = 2, labels = c("A","B")) 268 | 269 | # save 270 | plotFile <- mrggsave(list(plot_rhat, 271 | plot_neff, 272 | plot_mcmcHistory, 273 | plot_mcmcDensityByChain, 274 | plot_mcmcDensity, 275 | plot_historyDensity), 276 | scriptName, 277 | dir = figDir, stem = paste(modelName, "MCMCDiagnostics", sep = "-"), 278 | width = 10, height = 8, 279 | onefile = TRUE) 280 | 281 | plotFile_pairs <- mrggsave(list(plot_pairs), 282 | scriptName, 283 | dir = figDir, stem = paste(modelName, "MCMCDiagnostics-Corrs", sep = "-"), 284 | width = 14, height = 14, 285 | onefile = TRUE) 286 | 287 | ############# 288 | 289 | ## predictive checks ## 290 | # get cobsPred and cobsCond 291 | cobsCond.rep <- as_draws_matrix(fit$draws(variables = c("cObsCond"))) 292 | cobsPred.rep <- as_draws_matrix(fit$draws(variables = c("cObsPred"))) 293 | 294 | time <- data[["time"]] 295 | nSubject <- data[["nSubject"]] 296 | nObs <- data[["nObs"]] 297 | iObs <- data[["iObs"]] 298 | cObs <- data[["cObs"]] 299 | nti <- data[["nti"]] 300 | recByID <- unlist(sapply(1:nSubject, function(i){rep(i, nti[i])})) 301 | obsByID <- recByID[iObs] 302 | 303 | # plot_ppc_cobsCond <- ppc_ribbon_grouped(y=data[["cObs"]], yrep=cobsCond.rep, x=time[iObs], 304 | # group=obsByID) + scale_x_continuous(name="Time (h)") + 305 | # scale_y_continuous(name="Mavoglurant concentration (ng/mL)", trans = "log10") + theme(axis.text=element_text(size=10)) 306 | # 307 | plot_ppc_cobsPred <- ppc_ribbon_grouped(y=data[["cObs"]], yrep=cobsPred.rep, x=time[iObs], 308 | group=obsByID) + scale_x_continuous(name="Time (h)") + 309 | scale_y_continuous(name="Mavoglurant concentration (ng/mL)", trans = "log10") + theme(axis.text=element_text(size=10)) 310 | 311 | # ppc summary plot 312 | # get observed data 313 | df_cobs <- tibble(ID = obsByID, 314 | time = time[iObs], 315 | obs = cObs) %>% 316 | left_join(dat %>% mutate(ID2 = ID, ID = dense_rank(ID)) %>% select(ID, ID2, DOSE), by = "ID") %>% 317 | distinct() %>% 318 | mutate(dnobs = obs/DOSE) 319 | 320 | # get predictions 321 | df_cobsCond <- as_tibble(t(cobsCond.rep)) %>% 322 | mutate(ID = obsByID, time = time[iObs]) %>% 323 | gather(sim, pred, -ID, -time) %>% 324 | mutate(sim = as.integer(gsub("V","",sim))) %>% 325 | select(sim, ID, time, pred) %>% 326 | left_join(df_cobs %>% select(ID, ID2, DOSE), by = "ID") %>% 327 | distinct() %>% 328 | mutate(dnpred = pred/DOSE) 329 | 330 | df_cobsPred <- as_tibble(t(cobsPred.rep)) %>% 331 | mutate(ID = obsByID, time = time[iObs]) %>% 332 | gather(sim, pred, -ID, -time) %>% 333 | mutate(sim = as.integer(gsub("V","",sim))) %>% 334 | select(sim, ID, time, pred) %>% 335 | left_join(df_cobs %>% mutate(ID2 = ID, ID = dense_rank(ID)) %>% select(ID, ID2, DOSE), by = "ID") %>% 336 | distinct() %>% 337 | mutate(dnpred = pred/DOSE) 338 | 339 | plot_ppc_cobsPred_summ_byDose <- vpc(sim = df_cobsPred, 340 | obs = df_cobs, # supply simulation and observation dataframes 341 | obs_cols = list( 342 | id = "ID2", 343 | dv = "obs", # these column names are the default, 344 | idv = "time"), # update these if different. 345 | sim_cols = list( 346 | id = "ID2", 347 | dv = "pred", 348 | idv = "time", 349 | sim = "sim"), 350 | stratify = "DOSE", 351 | bins = c(0, 2, 4, 6, 8, 10, 20, 30, 40, 50), # specify bin separators manually 352 | pi = c(0.05, 0.95), # prediction interval simulated data to show 353 | ci = c(0.025, 0.975), # confidence intervals to show 354 | pred_corr = FALSE, # perform prediction-correction? 355 | show = list(obs_dv = TRUE), # plot observations? 356 | ylab = "Mavoglurant concentration (ng/mL)", 357 | xlab = "Time (h)") + 358 | scale_y_continuous(trans = "log10") + theme_bw() + theme(legend.text = element_text(size = 15), 359 | axis.title = element_text(size = 15)) 360 | 361 | plot_ppc_cobsPred_summ_total <- vpc(sim = df_cobsPred, 362 | obs = df_cobs, # supply simulation and observation dataframes 363 | obs_cols = list( 364 | id = "ID2", 365 | dv = "obs", # these column names are the default, 366 | idv = "time"), # update these if different. 367 | sim_cols = list( 368 | id = "ID2", 369 | dv = "pred", 370 | idv = "time", 371 | sim = "sim"), 372 | bins = c(0, 2, 4, 6, 8, 10, 20, 30, 40, 50), # specify bin separators manually 373 | pi = c(0.05, 0.95), # prediction interval simulated data to show 374 | ci = c(0.025, 0.975), # confidence intervals to show 375 | pred_corr = FALSE, # perform prediction-correction? 376 | show = list(obs_dv = TRUE), # plot observations? 377 | ylab = "Mavoglurant concentration (ng/mL)", 378 | xlab = "Time (h)") + 379 | scale_y_continuous(trans = "log10") + theme_bw() + theme(legend.text = element_text(size = 15), 380 | axis.title = element_text(size = 15)) 381 | 382 | plot_ppc_cobsPred_summ_total_dosenorm <- vpc(sim = df_cobsPred, 383 | obs = df_cobs, # supply simulation and observation dataframes 384 | obs_cols = list( 385 | id = "ID2", 386 | dv = "dnobs", # these column names are the default, 387 | idv = "time"), # update these if different. 388 | sim_cols = list( 389 | id = "ID2", 390 | dv = "dnpred", 391 | idv = "time", 392 | sim = "sim"), 393 | bins = c(0, 2, 4, 6, 8, 10, 20, 30, 40, 50), # specify bin separators manually 394 | pi = c(0.05, 0.95), # prediction interval simulated data to show 395 | ci = c(0.025, 0.975), # confidence intervals to show 396 | pred_corr = FALSE, # perform prediction-correction? 397 | show = list(obs_dv = TRUE), # plot observations? 398 | ylab = "Mavoglurant dose-normalized concentration (ng/mL/mg)", 399 | xlab = "Time (h)") + 400 | scale_y_continuous(trans = "log10", limits = c(0.01,100)) + theme_bw() + theme(legend.text = element_text(size = 15), 401 | axis.title = element_text(size = 15)) 402 | 403 | # individual plots 404 | df_cobsAll <- df_cobsCond %>% 405 | rename(cCond = pred) %>% 406 | bind_cols(df_cobsPred %>% 407 | select(cPred = pred)) 408 | 409 | df_cobsAll_summ <- df_cobsAll %>% 410 | group_by(ID, time) %>% 411 | mutate(loCond = lo(cCond), 412 | medCond = med(cCond), 413 | hiCond = hi(cCond), 414 | loPred = lo(cPred), 415 | medPred = med(cPred), 416 | hiPred = hi(cPred)) %>% 417 | slice(1) %>% 418 | ungroup() 419 | 420 | # join with observed 421 | df_simobs <- bind_cols(df_cobsAll_summ, df_cobs %>% select(cObs = obs)) 422 | 423 | # plot 424 | plot_ind <- ggplot(data=df_simobs, aes(x=time)) + 425 | geom_point(aes(y=cObs)) + 426 | geom_line(aes(y=medCond, color="Individual")) + 427 | geom_ribbon(aes(ymin = loCond, ymax=hiCond, fill="Individual"), alpha=0.2) + 428 | geom_line(aes(y=medPred, color="Population")) + 429 | geom_ribbon(aes(ymin = loPred, ymax=hiPred, fill="Population"), alpha=0.2) + 430 | facet_wrap(~ID2, ncol = 5) + 431 | scale_y_continuous(trans="log10") + 432 | scale_color_manual(name="", values = c("Individual" = "red", "Population" = "blue")) + 433 | scale_fill_manual(name="", values = c("Individual" = "red", "Population" = "blue")) + 434 | labs(x="Time (h)", y="Mavoglurant concentration (ng/mL)") + 435 | theme_bw() + 436 | theme(legend.position = "top", 437 | legend.text = element_text(size = 15), 438 | axis.title = element_text(size = 15)) 439 | 440 | # save 441 | plotFile <- mrggsave(list(plot_ppc_cobsPred, 442 | plot_ppc_cobsPred_summ_total, 443 | plot_ppc_cobsPred_summ_total_dosenorm, 444 | plot_ppc_cobsPred_summ_byDose, 445 | plot_ind), 446 | scriptName, 447 | dir = figDir, stem = paste(modelName,"PPC", sep = "-"), 448 | onefile = TRUE, 449 | width=10, height=8) 450 | 451 | } 452 | -------------------------------------------------------------------------------- /script/mavoPBPKGenODE_jl_postprocess.R: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ################################## Intro ####################################### 3 | ################################################################################ 4 | 5 | # This script does the post-processing of the mavoPBPKGenODE.jl model 6 | 7 | ################################################################################ 8 | ################################## setup ####################################### 9 | ################################################################################ 10 | 11 | rm(list=ls()) 12 | gc() 13 | 14 | library(tidyverse) 15 | library(vpc) 16 | library(posterior) 17 | library(bayesplot) 18 | library(cowplot) 19 | library(here) 20 | 21 | # environment 22 | modelName <- "mavoPBPKGenODE_jl" 23 | scriptName <- paste0(modelName, "_postprocess", ".R") 24 | 25 | setwd(here("script")) 26 | scriptDir <- getwd() 27 | projectDir <- dirname(scriptDir) 28 | figDir <- file.path(projectDir, "deliv", "figure", modelName) 29 | tabDir <- file.path(projectDir, "deliv", "table", modelName) 30 | 31 | #################### 32 | 33 | ## parameter tables ## 34 | 35 | ## read data 36 | df_params <- read.csv("../model/mavoPBPKGenODE_jl/df_params.csv") 37 | df_params2 <- as_draws_df(df_params) 38 | fitSummParams <- summarise_draws(df_params2) %>% 39 | mutate(ess_bulk_N = ess_bulk/1000, 40 | ess_tail_N = ess_tail/1000) 41 | write.csv(fitSummParams, file = file.path(tabDir, paste(modelName, "ParameterTable.csv", sep = "-")), quote = F, row.names = F) 42 | 43 | #################### 44 | 45 | ## neff_ratio 46 | fitSummParams2 <- fitSummParams %>% 47 | mutate(variable = factor(variable), 48 | variable = fct_relevel(variable, c("ĈLint","ω","σ","KbMU","KbAD","KbBO","KbRB","KbBR"))) 49 | 50 | fitSummParams3 <- fitSummParams %>% 51 | mutate(variable = factor(variable), 52 | variable = fct_relevel(variable, c("ω","ĈLint","KbBO","KbRB","KbMU","KbBR","σ","KbAD"))) 53 | 54 | fitSummParams4 <- fitSummParams %>% 55 | mutate(variable = factor(variable), 56 | variable = fct_relevel(variable, c("KbMU","KbBR","σ","ω","KbAD","KbRB","ĈLint","KbBO"))) 57 | 58 | plot_neff_ratio_bulk <- ggplot(data=fitSummParams2, aes(x=variable, y=ess_bulk_N, label=ess_bulk_N, color=ess_bulk_N)) + 59 | geom_point(stat="identity") + 60 | geom_segment(aes(y=0, 61 | x=variable, 62 | yend=ess_bulk_N, 63 | xend = variable)) + 64 | geom_hline(yintercept = c(0.1,0.5,1), lty=2, alpha=0.2) + 65 | coord_flip() + 66 | theme_bw() + 67 | theme(legend.position = "none") + 68 | labs(y="Neff-bullk/N", x="") + 69 | scale_y_continuous(breaks = c(0.1,0.5,1)) 70 | 71 | plot_neff_ratio_tail <- ggplot(data=fitSummParams3, aes(x=variable, y=ess_tail_N, label=ess_tail_N, color=ess_tail_N)) + 72 | geom_point(stat="identity") + 73 | geom_segment(aes(y=0, 74 | x=variable, 75 | yend=ess_tail_N, 76 | xend = variable)) + 77 | geom_hline(yintercept = c(0.1,0.5,1), lty=2, alpha=0.2) + 78 | coord_flip() + 79 | theme_bw() + 80 | theme(legend.position = "none") + 81 | labs(y="Neff-tail/N", x="") + 82 | scale_y_continuous(breaks = c(0.1,0.5,1)) 83 | 84 | plot_rhat <- ggplot(data=fitSummParams4, aes(x=variable, y=rhat, label=rhat, color=rhat)) + 85 | geom_point(stat="identity") + 86 | geom_segment(aes(y=1, 87 | x=variable, 88 | yend=rhat, 89 | xend = variable)) + 90 | geom_hline(yintercept = c(1,1.05), lty=2, alpha=0.2) + 91 | coord_flip() + 92 | theme_bw() + 93 | theme(legend.position = "none") + 94 | labs(y="Neff-tail/N", x="") + 95 | scale_y_continuous(breaks = c(1,1.05), 96 | limits = c(0.99,1.05)) 97 | 98 | plot_diag <- plot_grid(plot_rhat, plot_neff_ratio_bulk, plot_neff_ratio_tail, ncol = 3) 99 | 100 | # save 101 | plotFile <- mrggsave(list(plot_diag), 102 | scriptName, 103 | dir = figDir, stem = paste("diag"), 104 | onefile = TRUE, 105 | width=7, height=4) 106 | 107 | #################### 108 | 109 | ## individual plots ## 110 | df_simobs <- read.csv("../model/mavoPBPKGenODE_jl/df_ind.csv") 111 | 112 | # plot 113 | plot_ind_julia <- ggplot(data=df_simobs, aes(x=TIME)) + 114 | geom_point(aes(y=DV)) + 115 | geom_line(aes(y=medCond, color="Individual")) + 116 | geom_ribbon(aes(ymin = loCond, ymax=hiCond, fill="Individual"), alpha=0.2) + 117 | geom_line(aes(y=medPred, color="Population")) + 118 | geom_ribbon(aes(ymin = loPred, ymax=hiPred, fill="Population"), alpha=0.2) + 119 | facet_wrap(~ID, ncol = 5) + 120 | scale_y_continuous(trans="log10") + 121 | scale_color_manual(name="", values = c("Individual" = "red", "Population" = "blue")) + 122 | scale_fill_manual(name="", values = c("Individual" = "red", "Population" = "blue")) + 123 | labs(x="Time (h)", y="Mavoglurant concentration (ng/mL)") + 124 | theme_bw() + 125 | theme(legend.position = "top", 126 | legend.text = element_text(size = 15), 127 | axis.title = element_text(size = 15)) 128 | 129 | # save 130 | plotFile <- mrggsave(list(plot_ind_julia), 131 | scriptName, 132 | dir = figDir, stem = paste("PPCind"), 133 | onefile = TRUE, 134 | width=10, height=8) 135 | 136 | # ################### 137 | # 138 | # ## vpc ## 139 | # 140 | # # get observed data 141 | # ## load mavoglurant data 142 | # dat <- read.csv(file.path(dataDir, "Mavoglurant_A2121_nmpk.csv")) %>% 143 | # # 15 is venous blood compartment ; intravenous administration ; for evid=0 it won't matter but needs to be > 0 144 | # mutate(CMT = 15, 145 | # excl = ifelse(DV <= 0 & EVID == 0, 1, 0)) %>% 146 | # # grab the first 20 subjects 147 | # filter(ID <= 812, 148 | # excl == 0) %>% 149 | # select(-excl) 150 | # 151 | # df_cobs <- dat %>% 152 | # filter(EVID == 0) %>% 153 | # select(ID, time=TIME, DOSE, obs=DV) %>% 154 | # mutate(dnobs = obs/DOSE) 155 | # 156 | # ## read predictions 157 | # df_pred <- read.csv("../model/mavoPBPKGenODE_jl/df_pred.csv") 158 | # 159 | # # vpc 160 | # plot_ppc_cobsPred_dosenorm_julia <- vpc(sim = df_pred, 161 | # obs = df_cobs, # supply simulation and observation dataframes 162 | # obs_cols = list( 163 | # id = "ID", 164 | # dv = "dnobs", # these column names are the default, 165 | # idv = "time"), # update these if different. 166 | # sim_cols = list( 167 | # id = "ID", 168 | # dv = "DNDV", 169 | # idv = "TIME", 170 | # sim = "iteration"), 171 | # bins = c(0, 2, 4, 6, 8, 10, 20, 30, 40, 50), # specify bin separators manually 172 | # pi = c(0.05, 0.95), # prediction interval simulated data to show 173 | # ci = c(0.025, 0.975), # confidence intervals to show 174 | # pred_corr = FALSE, # perform prediction-correction? 175 | # show = list(obs_dv = TRUE), # plot observations? 176 | # ylab = "Mavoglurant dose-normalized concentration (ng/mL/mg)", 177 | # xlab = "Time (h)") + 178 | # scale_y_continuous(trans = "log10", limits = c(0.01,100)) 179 | # 180 | # # save 181 | # plotFile <- mrggsave(list(plot_ppc_cobsPred_dosenorm_julia), 182 | # scriptName, 183 | # dir = figDir, stem = paste(modelName,"PPC", sep = "-"), 184 | # onefile = TRUE, 185 | # width=10, height=8) 186 | 187 | -------------------------------------------------------------------------------- /script/mavoPBPKGenODE_run.jl: -------------------------------------------------------------------------------- 1 | #= 2 | Version: October 7, 2022 3 | 4 | Online supplement to the tutorial: 5 | 6 | Bayesian PBPK Modeling using R/Stan/Torsten and Julia/SciML/Turing.jl 7 | 8 | This script runs the Bayesian PBPK modeling in Julia/SciML/Turing.jl 9 | =# 10 | 11 | # activate pkg environment and load libraries 12 | # libraries are referenced in the Project.toml file 13 | cd(@__DIR__) 14 | cd("..") 15 | using Pkg; Pkg.activate(".") 16 | using CSV, DataFramesMeta, Chain, Random 17 | using OrdinaryDiffEq, DiffEqCallbacks, Turing, Distributions, CategoricalArrays 18 | using GlobalSensitivity, QuadGK 19 | using Plots, StatsPlots, MCMCChains 20 | using LinearAlgebra 21 | using Gadfly 22 | import Cairo, Fontconfig 23 | 24 | # set seed for reproducibility 25 | Random.seed!(123) 26 | 27 | # set paths 28 | modDir = "model" 29 | modName = "mavoPBPKGenODE" 30 | tabDir = joinpath("deliv","table") 31 | figDir = joinpath("deliv","figure") 32 | modPath = mkpath(joinpath(modDir, string(modName, "_jl"))) 33 | figPath = mkpath(joinpath(figDir, string(modName, "_jl"))) 34 | tabPath = mkpath(joinpath(tabDir, string(modName, "_jl"))) 35 | 36 | # read mavoglurant Study A2121 data; we'll only use the first 20 subjects 37 | dat_orig = CSV.read("data/Mavoglurant_A2121_nmpk.csv", DataFrame) 38 | dat = dat_orig[dat_orig.ID .<= 812,:] 39 | dat_obs = dat[dat.MDV .== 0,:] # grab first 20 subjects ; remove missing obs 40 | 41 | # load model function 42 | include(joinpath("..", modDir, string(modName, ".jl"))) 43 | 44 | # set simulation conditions 45 | nSubject = length(unique(dat.ID)) 46 | doses = dat.AMT[dat.EVID .== 1,:] 47 | rates = dat.RATE[dat.EVID .== 1,:] 48 | durs = doses ./ rates 49 | ncmt = 16 50 | u0 = zeros(ncmt) 51 | tspan = (0.0,maximum(dat.TIME)) 52 | times = [] 53 | for i in unique(dat_obs.ID); push!(times, dat_obs.TIME[dat_obs.ID .== i]); end 54 | 55 | # fixed parameters 56 | wts = dat.WT[dat.EVID .== 1,:] 57 | VVBs = (5.62 .* wts ./ 100) ./ 1.040 # volume of venous blood 58 | BP = 0.61 # blood:plasma concentration ratio 59 | 60 | # callback function for infusion stopping via zeroing k₀ parameter at end of infusion 61 | function affect!(integrator) 62 | integrator.p[8] = integrator.p[8] == 0.0 63 | end 64 | cbs = [] 65 | for i in 1:length(unique(dat.ID)); push!(cbs, PresetTimeCallback([durs[i]], affect!)); end 66 | 67 | # params to be estimated 68 | CLint = exp(7.1) 69 | KbBR = exp(1.1); 70 | KbMU = exp(0.3); 71 | KbAD = exp(2); 72 | KbBO = exp(0.03); 73 | KbRB = exp(0.3); 74 | p = [CLint, KbBR, KbMU, KbAD, KbBO, KbRB, wts[1], rates[1]] 75 | 76 | # define the ODE problem 77 | prob = ODEProblem(PBPKODE!, u0, tspan, p) 78 | 79 | ######## 80 | 81 | ## global sensitivity analysis ## 82 | ## create function that takes in paramers and returns endpoints for sensitivity (AUC in ths case) 83 | p_sens = p[1:6] 84 | f_globsens = function(p_sens) 85 | p_all = [p_sens;[wts[1],rates[1]]] 86 | tmp_prob = remake(prob, p = p_all) 87 | tmp_sol = solve(tmp_prob, Tsit5(), save_idxs=[15], callback=cbs[1]) 88 | auc, err = quadgk(tmp_sol, 0.0, 48.0) 89 | return(auc[1]) 90 | end 91 | 92 | ### conditions 93 | n = 1000 # number of initial samples 94 | lb = [1000.0, 1.0, 1.0, 1.0, 1.0, 1.0] # parameter lower bounds 95 | ub = [1500.0, 10.0, 10.0, 10.0, 10.0, 10.0] # parameter upper bounds 96 | sampler = GlobalSensitivity.SobolSample() 97 | A, B = GlobalSensitivity.QuasiMonteCarlo.generate_design_matrices(n, lb, ub, sampler) # create the parameter set matrices to be passed to the gsa function 98 | 99 | #### Sobol global sensitivity analysis 100 | @time s = GlobalSensitivity.gsa(f_globsens, Sobol(), A, B) 101 | 102 | #### plot 103 | plot_sens_total = Plots.bar(["CLint","KbBR","KbMU","KbAD","KbBO","KbRB"], s.ST, title="Total Order Indices", ylabel="Index", legend=false) 104 | Plots.hline!([0.05], linestyle=:dash) 105 | plot_sens_single = Plots.bar(["CLint","KbBR","KbMU","KbAD","KbBO","KbRB"], s.S1, title="First Order Indices", ylabel="Index", legend=false) 106 | Plots.hline!([0.05], linestyle=:dash) 107 | 108 | plot_sens = Plots.plot(plot_sens_single, plot_sens_total, xrotation = 45) 109 | savefig(plot_sens, joinpath(figPath, "sensitivity.pdf")) 110 | 111 | ####### 112 | 113 | ## Bayesian inference ## 114 | 115 | ## define Bayesian model function 116 | @model function fitPBPK(data, prob, nSubject, rates, times, wts, cbs, VVBs, BP) # data should be a Vector 117 | # priors 118 | ## informative priors for fixed effects and semi-informative for random effects 119 | σ ~ truncated(Cauchy(0, 0.5), 0.0, Inf) # residual error 120 | ĈLint ~ LogNormal(7.1,0.25) # intrinsic clearance 121 | KbBR ~ LogNormal(1.1,0.25) # brain to plasma partition coefficient 122 | KbMU ~ LogNormal(0.3,0.25) # muscle to plasma partition coefficient 123 | KbAD ~ LogNormal(2.0,0.25) # adipose to plasma partition coefficient 124 | KbBO ~ LogNormal(0.03, 0.25) # bone to plasma partition coefficient 125 | KbRB ~ LogNormal(0.3, 0.25) # rest of body to plasma partition coefficient 126 | ω ~ truncated(Cauchy(0, 0.5), 0.0, 1.0) # intersubject variability SD 127 | ηᵢ ~ filldist(Normal(0.0, 1.0), nSubject) # individual ηs for random effects 128 | 129 | # individual params 130 | CLintᵢ = ĈLint .* exp.(ω .* ηᵢ) # non-centered parameterization 131 | 132 | # function to update ODE problem with newly sampled params 133 | function prob_func(prob,i,repeat) 134 | ps = [CLintᵢ[i], KbBR, KbMU, KbAD, KbBO, KbRB, wts[i], rates[i]] 135 | remake(prob, p=ps, saveat=times[i], callback=cbs[i]) 136 | end 137 | 138 | # define an ensemble problem and simulate the population 139 | tmp_ensemble_prob = EnsembleProblem(prob, prob_func=prob_func) 140 | # solving can be parallelized by replacing EnsembleSerial() with EnsembleThreads() but there is no need since chains will be parallelized later 141 | # and having nested parallelization might lead to non reproducible results 142 | tmp_ensemble_sol = solve(tmp_ensemble_prob, Tsit5(), EnsembleSerial(), trajectories=nSubject) 143 | 144 | # calculate predicted plasma concentration for the population and append in a vector 145 | predicted = [] 146 | for i in 1:nSubject 147 | times_tmp = times[i] 148 | idx = findall(x -> x in times_tmp, tmp_ensemble_sol[i].t) 149 | tmp_sol = Array(tmp_ensemble_sol[i])[15,idx] ./ (VVBs[i]*BP/1000.0) 150 | append!(predicted, tmp_sol) 151 | end 152 | 153 | # likelihood 154 | for i = 1:length(predicted) 155 | data[i] ~ LogNormal(log.(max(predicted[i], 1e-12)), σ) 156 | end 157 | end 158 | 159 | # define the Bayesian model object 160 | mod = fitPBPK(dat_obs.DV, prob, nSubject, rates, times, wts, cbs, VVBs, BP) 161 | 162 | # sample ; caution: sampling might take several hours to finish 163 | # you can skip sampling and go directly to lines 182 and 183 to load saved samples 164 | ## sampling conditions 165 | nsampl = 250 166 | nchains = 4 167 | adapt_delta = .8 168 | 169 | ## sampling in serial 170 | #@time mcmcchains = sample(mod, NUTS(nsampl,adapt_delta), MCMCSerial(), nsampl, nchains) 171 | #@time mcmcchains_prior = sample(mod, Prior(), MCMCSerial(), nsampl, nchains) # parallel 172 | 173 | ## sampling with multithreading 174 | @time mcmcchains = sample(mod, NUTS(nsampl,adapt_delta), MCMCThreads(), nsampl, nchains) 175 | @time mcmcchains_prior = sample(mod, Prior(), MCMCThreads(), nsampl, nchains) # parallel 176 | 177 | ## save mcmcchains; uncomment to save generated chains; caution: this will overwrite the already saved chains 178 | #write(joinpath(modPath, string(modName, "chains.jls")), mcmcchains) 179 | #write(joinpath(modPath, string(modName, "chains_prior.jls")), mcmcchains_prior) 180 | 181 | ##uncomment to load saved chains 182 | #mcmcchains = read(joinpath(modPath, string(modName, "chains.jls")), Chains) 183 | #mcmcchains_prior = read(joinpath(modPath, string(modName, "chains_prior.jls")), Chains) 184 | 185 | 186 | #---# diagnostics #---# 187 | # tables 188 | summ, quant = describe(mcmcchains) 189 | #summ, quant = describe(mcmcchains; q = [0.05, 0.25, 0.5, 0.75, 0.95]) # control quantiles in output 190 | 191 | ## summary 192 | df_summ = DataFrame(summ) 193 | CSV.write(joinpath(tabPath, "Summary.csv"), df_summ) 194 | 195 | ## quantiles 196 | df_quant = DataFrame(quant) 197 | CSV.write(joinpath(tabPath, "Quantiles.csv"), df_quant) 198 | 199 | # plots 200 | ## trace plots ; we will split plots and join later for better view 201 | #plot_chains = StatsPlots.plot(mcmcchains[:,1:8,:]) # mcmcchains[samples, params, chains] 202 | plot_chains1 = StatsPlots.plot(mcmcchains[:,1:4,:]) 203 | plot_chains2 = StatsPlots.plot(mcmcchains[:,5:8,:]) 204 | plot_chains = Plots.plot(plot_chains1, plot_chains2, layout = (1,2)) 205 | savefig(plot_chains, joinpath(figPath, "MCMCTrace.pdf")) 206 | 207 | ## density plots 208 | p_post = zeros(nsampl, 8, 4) 209 | p_prior = deepcopy(p_post) 210 | 211 | for i in 1:4; p_post[:,:,i] = Array(mcmcchains[:,1:8,1]); end 212 | for i in 1:4; p_prior[:,:,i] = Array(mcmcchains_prior[:,1:8,1]); end 213 | 214 | p_post_mean = mean(p_post, dims=3)[:,:,1] 215 | p_prior_mean = mean(p_prior, dims=3)[:,:,1] 216 | 217 | pars = summ[1:8,1] 218 | dens_plots = [] 219 | for i in 1:8; p = density(p_post_mean[:,i], title=pars[i], label="Posterior"); density!(p_prior_mean[:,i], label="Prior"); push!(dens_plots, p); end 220 | 221 | dens_plots[1] = Plots.plot(dens_plots[1], xlims=(0.0,0.6)) 222 | 223 | plot_dens = Plots.plot(dens_plots[1], 224 | dens_plots[2], 225 | dens_plots[3], 226 | dens_plots[4], 227 | dens_plots[5], 228 | dens_plots[6], 229 | dens_plots[7], 230 | dens_plots[8], 231 | layout=grid(4,2), 232 | size = (650,650)) 233 | savefig(plot_dens, joinpath(figPath, "DensPlots.pdf")) 234 | 235 | #---# predictive checks #---# 236 | 237 | #= 238 | Predicitive checks can be conditioned on sampled parameters or on samples from a new population. 239 | Here, we will do both. 240 | =# 241 | 242 | #--# conditional on chains #--# 243 | 244 | # we will first create a vector of "missing" values to pass to the Bayesian fit function 245 | # Turing will understand that the created model object is meant to simulate rather than fit 246 | dat_missing = Vector{Missing}(missing, length(dat_obs.DV)) # vector of `missing` 247 | mod_pred = fitPBPK(dat_missing, prob, nSubject, rates, times, wts, cbs, VVBs, BP) 248 | #pred = predict(mod_pred, mcmcchains) # posterior ; conditioned on each sample in chains 249 | pred = predict(mod_pred, mcmcchains, include_all=false) # include_all = false means sampling new !! 250 | #pred_prior = predict(mod_pred, mcmcchains_prior) 251 | 252 | ### predictive checks summaries 253 | #summarystats(pred) 254 | summ_pred, quant_pred = describe(pred) 255 | #summarystats(pred_prior) 256 | #summ_pred_prior, quant_pred_prior = describe(pred_prior) 257 | 258 | #### save 259 | #CSV.write(joinpath(tabPath, "Summary_PPC.csv"), summ_pred) 260 | #CSV.write(joinpath(tabPath, "Quantiles_PPC.csv"), quant_pred) 261 | 262 | # data assembly to summarise and bring observed and predicted data together 263 | bins = [0, 1, 2, 3, 4, 6, 8, 10, 20, 30, 40, 50] 264 | labels = string.(1:length(bins) - 1) 265 | 266 | ## observed 267 | df_vpc_obs = @chain begin 268 | dat_obs 269 | @select(:ID, :TIME, :DV, :DOSE) 270 | @transform(:DNDV = :DV ./ :DOSE, 271 | :bins = cut(:TIME, bins, labels = labels)) 272 | 273 | groupby(:bins) 274 | @transform(:lo = quantile(:DNDV, 0.05), 275 | :med = quantile(:DNDV, 0.5), 276 | :hi = quantile(:DNDV, 0.95)) 277 | end 278 | df_vpc_obs2 = @orderby(unique(@select(df_vpc_obs, :TIME, :bins, :lo, :med, :hi)), :TIME) 279 | 280 | ## predicted 281 | df_pred = DataFrame(pred) 282 | df_vpc_pred = @chain begin 283 | df_pred 284 | DataFramesMeta.stack(3:ncol(df_pred)) 285 | @orderby(:iteration, :chain) 286 | hcat(select(repeat(dat_obs, 1000), [:ID,:TIME,:DOSE])) 287 | @transform(:DNDV = :value ./ :DOSE, 288 | :bins = cut(:TIME, bins, labels = labels)) 289 | 290 | groupby([:iteration, :chain, :bins]) 291 | @transform(:lo = quantile(:DNDV, 0.05), 292 | :med = quantile(:DNDV, 0.5), 293 | :hi = quantile(:DNDV, 0.95)) 294 | 295 | groupby(:bins) 296 | @transform(:loLo = quantile(:lo, 0.025), 297 | :medLo = quantile(:lo, 0.5), 298 | :hiLo = quantile(:lo, 0.975), 299 | :loMed = quantile(:med, 0.025), 300 | :medMed = quantile(:med, 0.5), 301 | :hiMed = quantile(:med, 0.975), 302 | :loHi = quantile(:hi, 0.025), 303 | :medHi = quantile(:hi, 0.5), 304 | :hiHi = quantile(:hi, 0.975)) 305 | end 306 | 307 | df_vpc_pred2 = @orderby(unique(df_vpc_pred[!,[6;13:21]]), :TIME) 308 | 309 | ### plot 310 | dat_obs2 = @transform(dat_obs, :DNDV = :DV ./ :DOSE) 311 | 312 | set_default_plot_size(17cm, 12cm) 313 | 314 | plot_ppc = Gadfly.plot(x=dat_obs2.TIME, y=dat_obs2.DNDV, Geom.point, Scale.y_log10, Theme(background_color="white", default_color="black"), alpha=[0.2], Guide.xlabel("Time (h)"), Guide.ylabel("Mavoglurant dose-normalized concentration (ng/mL/mg)", orientation=:vertical), 315 | layer(x=df_vpc_obs.TIME, y=df_vpc_obs.med, Geom.line, Theme(default_color="black")), 316 | layer(x=df_vpc_obs.TIME, y=df_vpc_obs.lo, Geom.line, Theme(default_color="black")), 317 | layer(x=df_vpc_obs.TIME, y=df_vpc_obs.hi, Geom.line, Theme(default_color="black")), 318 | layer(x=df_vpc_pred2.TIME, ymin=df_vpc_pred2.loMed, ymax=df_vpc_pred2.hiMed, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.8]), 319 | layer(x=df_vpc_pred2.TIME, ymin=df_vpc_pred2.loLo, ymax=df_vpc_pred2.hiLo, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.5]), 320 | layer(x=df_vpc_pred2.TIME, ymin=df_vpc_pred2.loHi, ymax=df_vpc_pred2.hiHi, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.5])) 321 | 322 | plot_tmp = PDF(joinpath(figPath, "PPCCond.pdf"), 17cm, 12cm) 323 | draw(plot_tmp, plot_ppc) 324 | 325 | 326 | #--# new population #--# 327 | 328 | df_params = DataFrame(mcmcchains)[:,3:10] 329 | 330 | # save CSV; caution: uncommenting this will overwrite the already saved df_params.csv file 331 | #CSV.write(joinpath(modPath, "df_params.csv"), df_params) 332 | 333 | ## new etas for a new population 334 | ηs = reshape(rand(Normal(0.0, 1.0), nSubject*nrow(df_params)), nrow(df_params), nSubject) 335 | 336 | # run simulations for the new population 337 | array_pred = Array{Float64}(undef, nrow(df_params), nrow(dat_obs)) 338 | 339 | for j in 1:nrow(df_params) 340 | KbBR = df_params[j,:KbBR] 341 | KbMU = df_params[j,:KbMU] 342 | KbAD = df_params[j,:KbAD] 343 | KbBO = df_params[j,:KbBO] 344 | KbRB = df_params[j,:KbRB] 345 | 346 | CLintᵢ = df_params[j,:ĈLint] .* exp.(df_params[j,:ω] .* ηs[j,:]) 347 | 348 | # simulate 349 | function prob_func(prob,i,repeat) 350 | ps = [CLintᵢ[i], KbBR, KbMU, KbAD, KbBO, KbRB, wts[i], rates[i]] 351 | remake(prob, p=ps, saveat=times[i], callback=cbs[i]) 352 | end 353 | 354 | tmp_ensemble_prob = EnsembleProblem(prob, prob_func=prob_func) 355 | tmp_ensemble_sol = solve(tmp_ensemble_prob, Tsit5(), trajectories=nSubject) 356 | 357 | predicted = [] 358 | for i in 1:nSubject 359 | times_tmp = times[i] 360 | idx = findall(x -> x in times_tmp, tmp_ensemble_sol[i].t) 361 | tmp_sol = Array(tmp_ensemble_sol[i])[15,idx] ./ (VVBs[i]*BP/1000.0) 362 | append!(predicted, tmp_sol) 363 | end 364 | 365 | array_pred[j, :] = rand.(LogNormal.(log.(predicted), df_params[j,:σ])) 366 | end 367 | 368 | df_pred_new = DataFrame(array_pred, :auto) 369 | @transform!(df_pred_new, :iteration = 1:size(array_pred)[1]) 370 | 371 | # save version for R's vpc 372 | df_pred_new2 = @chain begin 373 | df_pred_new 374 | DataFramesMeta.stack(1:268) 375 | @orderby(:iteration) 376 | hcat(select(repeat(dat_obs, 1000), [:ID,:TIME,:DOSE])) 377 | @transform(:DNDV = :value ./ :DOSE) 378 | end 379 | 380 | # save CSV 381 | #CSV.write(joinpath(modPath, "df_pred.csv"), df_pred_new2) 382 | 383 | # create the new population predictions dataframe 384 | df_vpc_pred_new = @chain begin 385 | df_pred_new 386 | DataFramesMeta.stack(1:268) 387 | @orderby(:iteration) 388 | hcat(select(repeat(dat_obs, 1000), [:ID,:TIME,:DOSE])) 389 | @transform(:DNDV = :value ./ :DOSE, 390 | :bins = cut(:TIME, bins, labels = labels)) 391 | 392 | groupby([:iteration, :bins]) 393 | @transform(:lo = quantile(:DNDV, 0.05), 394 | :med = quantile(:DNDV, 0.5), 395 | :hi = quantile(:DNDV, 0.95)) 396 | 397 | groupby(:bins) 398 | @transform(:loLo = quantile(:lo, 0.025), 399 | :medLo = quantile(:lo, 0.5), 400 | :hiLo = quantile(:lo, 0.975), 401 | :loMed = quantile(:med, 0.025), 402 | :medMed = quantile(:med, 0.5), 403 | :hiMed = quantile(:med, 0.975), 404 | :loHi = quantile(:hi, 0.025), 405 | :medHi = quantile(:hi, 0.5), 406 | :hiHi = quantile(:hi, 0.975)) 407 | end 408 | 409 | df_vpc_pred_new2 = @orderby(unique(df_vpc_pred_new[!,[5;12:20]]), :TIME) 410 | 411 | ### plot 412 | #dat_obs2 = @transform(dat_obs, :DNDV = :DV ./ :DOSE) 413 | 414 | set_default_plot_size(17cm, 12cm) 415 | 416 | plot_ppc_new = Gadfly.plot(x=dat_obs2.TIME, y=dat_obs2.DNDV, Geom.point, Scale.y_log10, Theme(background_color="white", default_color="black"), alpha=[0.2], Guide.xlabel("Time (h)"), Guide.ylabel("Mavoglurant dose-normalized concentration (ng/mL/mg)", orientation=:vertical), 417 | layer(x=df_vpc_obs.TIME, y=df_vpc_obs.med, Geom.line, Theme(default_color="black")), 418 | layer(x=df_vpc_obs.TIME, y=df_vpc_obs.lo, Geom.line, Theme(default_color="black")), 419 | layer(x=df_vpc_obs.TIME, y=df_vpc_obs.hi, Geom.line, Theme(default_color="black")), 420 | layer(x=df_vpc_pred_new2.TIME, ymin=df_vpc_pred_new2.loMed, ymax=df_vpc_pred_new2.hiMed, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.8]), 421 | layer(x=df_vpc_pred_new2.TIME, ymin=df_vpc_pred_new2.loLo, ymax=df_vpc_pred_new2.hiLo, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.5]), 422 | layer(x=df_vpc_pred_new2.TIME, ymin=df_vpc_pred_new2.loHi, ymax=df_vpc_pred_new2.hiHi, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.5])) 423 | 424 | plot_tmp = PDF(joinpath(figPath, "PPCPred.pdf"), 17cm, 12cm) 425 | draw(plot_tmp, plot_ppc_new) 426 | 427 | #--# individual plots #--# 428 | 429 | df_cObs = @chain begin 430 | df_vpc_obs 431 | @select(:ID,:TIME,:DV,:DOSE) 432 | end 433 | 434 | # conditioned on individual data 435 | df_cCond = @chain begin 436 | df_vpc_pred 437 | groupby([:ID,:TIME]) 438 | @transform(:loCond = quantile(:value, 0.05), 439 | :medCond = quantile(:value, 0.5), 440 | :hiCond = quantile(:value, 0.95)) 441 | @select(:ID, :TIME, :DOSE, :loCond, :medCond, :hiCond) 442 | unique() 443 | end 444 | 445 | # conditioned on individuals in a new population 446 | df_cPred = @chain begin 447 | df_vpc_pred_new 448 | groupby([:ID,:TIME]) 449 | @transform(:loPred = quantile(:value, 0.05), 450 | :medPred = quantile(:value, 0.5), 451 | :hiPred = quantile(:value, 0.95)) 452 | @select(:ID, :TIME, :DOSE, :loPred, :medPred, :hiPred) 453 | unique() 454 | end 455 | 456 | # join all data 457 | df_cAll = hcat(df_cObs, 458 | @select(df_cCond, :loCond, :medCond, :hiCond), 459 | @select(df_cPred, :loPred, :medPred, :hiPred)) 460 | 461 | # save CSV for plotting in R 462 | CSV.write(joinpath(modPath, "df_ind.csv"), df_cAll) 463 | 464 | ####### 465 | 466 | ## simulation ## 467 | 468 | ### use the sampled parameters to run simulations for an alternative dosing scenario: 469 | ### 500 mg single infusion dose administered to 500 subjects 470 | 471 | # get wts for 500 individuals 472 | wts_sim = @chain begin 473 | dat_orig 474 | @subset(:EVID .== 1) 475 | unique(:ID) 476 | @select(:WT) 477 | Array 478 | end 479 | wts_sim = sample(wts_sim, 500, replace=true) 480 | vvbs_sim = (5.62 .* wts_sim ./ 100) ./ 1.040 481 | 482 | # get 500 replicates of inferred parameters 483 | df_params_sim1 = DataFrame(mcmcchains)[:,3:10] 484 | df_params_sim2 = df_params_sim1[sample(1:nrow(df_params_sim1), 500, replace=false),:] 485 | 486 | ## new etas 487 | ηs_sim = reshape(rand(Normal(0.0, 1.0), 500*500), 500, 500) 488 | 489 | # create array to hold results 490 | times_sim = [0.0:0.1:48.0;] 491 | array_pred_sim = Array{Float64}(undef, 500, length(times_sim)*500) 492 | 493 | # simulate a 50 mg single 494 | ## infusion callback 495 | dose = 50.0 496 | cb = PresetTimeCallback([10.0/60.0], affect!) 497 | 498 | for j in 1:nrow(df_params_sim2) 499 | KbBR = df_params_sim2[j,:KbBR] 500 | KbMU = df_params_sim2[j,:KbMU] 501 | KbAD = df_params_sim2[j,:KbAD] 502 | KbBO = df_params_sim2[j,:KbBO] 503 | KbRB = df_params_sim2[j,:KbRB] 504 | 505 | CLintᵢ = df_params_sim2[j,:ĈLint] .* exp.(df_params_sim2[j,:ω] .* ηs_sim[j,:]) 506 | 507 | # simulate 508 | function prob_func_sim(prob,i,repeat) 509 | ps = [CLintᵢ[i], KbBR, KbMU, KbAD, KbBO, KbRB, wts_sim[i], 300.0] 510 | remake(prob, p=ps, tspan=(0.0,48.0)) 511 | end 512 | 513 | sim_ensemble_prob = EnsembleProblem(prob, prob_func=prob_func_sim) 514 | sim_ensemble_sol = solve(sim_ensemble_prob, Tsit5(), save_idxs=[15], callback=cb, saveat=times_sim, trajectories=nrow(df_params_sim2)) 515 | 516 | predicted = [] 517 | for i in 1:500 518 | idx = findall(x -> x in times_sim, sim_ensemble_sol[i].t) 519 | tmp_sol = Array(sim_ensemble_sol[i])[1,idx] ./ (vvbs_sim[i]*BP/1000.0) 520 | append!(predicted, tmp_sol) 521 | end 522 | 523 | array_pred_sim[j, :] = rand.(LogNormal.(log.(predicted), df_params_sim2[j,:σ])) 524 | end 525 | 526 | # get stats 527 | 528 | df_pred_sim = DataFrame(array_pred_sim, :auto) 529 | @transform!(df_pred_sim, :iteration = 1:size(array_pred_sim)[1]) 530 | 531 | df_pred_sim2 = @chain begin 532 | df_pred_sim 533 | DataFramesMeta.stack(1:240500) 534 | @orderby(:iteration) 535 | @transform(:ID = repeat(repeat(1:500,inner=length(times_sim)), 500), 536 | :TIME = repeat(times_sim, 500*500), 537 | :DOSE = dose) 538 | @transform(:DNDV = :value ./ :DOSE) 539 | 540 | groupby([:iteration, :TIME]) 541 | @transform(:lo = quantile(:value, 0.05), 542 | :med = quantile(:value, 0.5), 543 | :hi = quantile(:value, 0.95)) 544 | 545 | groupby(:TIME) 546 | @transform(:loLo = quantile(:lo, 0.025), 547 | :medLo = quantile(:lo, 0.5), 548 | :hiLo = quantile(:lo, 0.975), 549 | :loMed = quantile(:med, 0.025), 550 | :medMed = quantile(:med, 0.5), 551 | :hiMed = quantile(:med, 0.975), 552 | :loHi = quantile(:hi, 0.025), 553 | :medHi = quantile(:hi, 0.5), 554 | :hiHi = quantile(:hi, 0.975)) 555 | end 556 | 557 | df_pred_summ = @orderby(unique(df_pred_sim2[!,[5;11:19]]), :TIME) 558 | 559 | # save CSV 560 | #CSV.write(joinpath(modPath, "df_pred.csv"), df_pred_new2) 561 | 562 | ### plot 563 | #dat_obs2 = @transform(dat_obs, :DNDV = :DV ./ :DOSE) 564 | 565 | set_default_plot_size(17cm, 12cm) 566 | 567 | plot_pred_summ = Gadfly.plot(x=df_pred_summ.TIME, ymin=df_pred_summ.loMed, ymax=df_pred_summ.hiMed, Geom.ribbon, Scale.y_log10, Theme(default_color="deepskyblue", background_color="white"), alpha=[0.8], Guide.xlabel("Time (h)"), Guide.ylabel("Mavoglurant concentration (ng/mL)", orientation=:vertical), 568 | layer(x=df_pred_summ.TIME, ymin=df_pred_summ.loLo, ymax=df_pred_summ.hiLo, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.5]), 569 | layer(x=df_pred_summ.TIME, ymin=df_pred_summ.loHi, ymax=df_pred_summ.hiHi, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.5]), 570 | layer(x=df_pred_summ.TIME, y=df_pred_summ.medMed, Geom.line, Theme(default_color="black")), 571 | layer(x=df_pred_summ.TIME, y=df_pred_summ.medLo, Geom.line, Theme(default_color="black")), 572 | layer(x=df_pred_summ.TIME, y=df_pred_summ.medHi, Geom.line, Theme(default_color="black"))) 573 | 574 | plot_tmp = PDF(joinpath(figPath, "SimPred.pdf"), 17cm, 12cm) 575 | draw(plot_tmp, plot_pred_summ) 576 | 577 | 578 | 579 | -------------------------------------------------------------------------------- /script/mavoPBPKLinODE.R: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ################################## Intro ####################################### 3 | ################################################################################ 4 | 5 | # Version: October 20, 2022 6 | # 7 | # Online supplement to the tutorial: 8 | # 9 | # Bayesian PBPK Modeling using R/Stan/Torsten and Julia/SciML/Turing.jl 10 | # 11 | # This script runs the Bayesian PBPK modeling linear ODE in R/Stan/Torsten 12 | 13 | ################################################################################ 14 | ################################## setup ####################################### 15 | ################################################################################ 16 | 17 | # clear working environment 18 | rm(list = ls()) 19 | gc() 20 | 21 | # load libraries 22 | library(tidyverse) 23 | library(rstan) 24 | library(bayesplot) 25 | library(loo) 26 | library(parallel) 27 | library(future.apply) 28 | library(cmdstanr) 29 | library(posterior) 30 | library(vpc) 31 | library(mrggsave) 32 | library(cowplot) 33 | library(here) 34 | 35 | # set environment 36 | setwd(here("script")) 37 | modelName <- "mavoPBPKLinODE" 38 | scriptName <- paste(modelName, "R", sep = ".") 39 | 40 | ## Relative paths assuming the working directory is the script directory 41 | ## containing this script 42 | scriptDir <- getwd() 43 | projectDir <- dirname(scriptDir) 44 | figDir <- file.path(projectDir, "deliv", "figure", modelName) 45 | tabDir <- file.path(projectDir, "deliv", "table", modelName) 46 | dataDir <- file.path(projectDir, "data") 47 | derivedDataDir <- file.path(dataDir, "derived") 48 | sourceDataDir <- file.path(dataDir, "source") 49 | modelDir <- file.path(projectDir, "model") 50 | ## Path for cmdstan interface to Stan 51 | stanDir <- file.path(scriptDir, "Torsten", "cmdstan") 52 | outDir <- file.path(modelDir, modelName) 53 | toolsDir <- file.path(scriptDir, "tools") 54 | tempDir <- file.path(scriptDir, "temp") 55 | invisible(dir.create(tempDir,recursive=T)) 56 | invisible(dir.create(figDir,recursive=T)) 57 | invisible(dir.create(tabDir,recursive=T)) 58 | invisible(dir.create(outDir,recursive=T)) 59 | 60 | # other conditions 61 | # caution: if fitModel = TRUE, this will fit and overwrite the already saved fit object 62 | # if you only want to run the analysis on the already saved fit object, set fitModel <- FALSE and runAnalysis <- TRUE 63 | fitModel <- TRUE 64 | useRStan <- FALSE 65 | runAnalysis <- FALSE 66 | 67 | source(file.path(toolsDir, "stanTools.R")) 68 | source(file.path(toolsDir, "functions.R")) 69 | if(!useRStan) source(file.path(toolsDir, "cmdStanTools.R")) 70 | set_cmdstan_path(stanDir) 71 | 72 | rstan_options(auto_write = TRUE) 73 | options(mc.cores = parallel::detectCores()) 74 | 75 | set.seed(123) ## not required but assures repeatable results 76 | 77 | ################################################################################ 78 | ################################# Prepare data ################################# 79 | ################################################################################ 80 | 81 | ## load mavoglurant data 82 | dat <- read.csv(file.path(dataDir, "Mavoglurant_A2121_nmpk.csv")) %>% 83 | # 15 is venous blood compartment ; intravenous administration ; for evid=0 it won't matter but needs to be > 0 84 | mutate(CMT = 15, 85 | excl = ifelse(DV <= 0 & EVID == 0, 1, 0)) %>% 86 | # grab the first 20 subjects 87 | filter(ID <= 812, 88 | excl == 0) %>% 89 | select(-excl) 90 | 91 | ## explore observed data 92 | ggplot(data=dat %>% filter(EVID == 0), aes(x=TIME, y=DV, col=factor(ID))) + 93 | geom_line() + 94 | theme_bw() + 95 | theme(legend.position = "none") + 96 | scale_y_continuous(trans = "log10") 97 | 98 | ## prepare input data 99 | nt <- nrow(dat) 100 | start <- (1:nt)[!duplicated(dat$ID)] 101 | end <- c(start[-1] - 1, nt) 102 | nti <- end - start + 1 103 | nSubject <- length(unique(dat$ID)) 104 | weights <- dat %>% group_by(ID) %>% slice(1) %>% pull(WT) 105 | ii <- rep(0, nt) 106 | addl <- rep(0, nt) 107 | ss <- rep(0, nt) 108 | 109 | ## Indices of records containing observed concentrations 110 | iObs <- with(dat, (1:nrow(dat))[EVID == 0]) 111 | nObs <- length(iObs) 112 | 113 | ## create data set 114 | data <- with(dat, 115 | list( 116 | nSubject = nSubject, 117 | nt = nt, 118 | nObs = nObs, 119 | iObs = iObs, 120 | time = TIME, 121 | amt = AMT, 122 | rate = RATE, 123 | cmt = CMT, 124 | evid = EVID, 125 | ii = ii, 126 | addl = addl, 127 | ss = ss, 128 | start = start, 129 | end = end, 130 | nti = nti, 131 | weight = weights, 132 | cObs = DV[iObs] 133 | )) 134 | 135 | nIIV <- 1 136 | nTheta <- 6 137 | 138 | ## get inits 139 | init <- function(){ 140 | list(CLintHat = rlnorm(1, meanlog=7.1, sdlog=0.25), 141 | KbBR = rlnorm(1, meanlog=1.1, sdlog=0.25), 142 | KbMU = rlnorm(1, meanlog=0.3, sdlog=0.25), 143 | KbAD = rlnorm(1, meanlog=2, sdlog=0.25), 144 | KbBO = rlnorm(1, meanlog=0.03, sdlog=0.25), 145 | KbRB = rlnorm(1, meanlog=0.3, sdlog=0.25), 146 | #omega = exp(rnorm(nIIV, log(0.05), 0.5)), 147 | omega = exp(rnorm(nIIV, log(0.25), 0.25)), 148 | L = diag(nIIV), 149 | sigma = runif(1, 0.25, 1), 150 | etaStd = matrix(rep(0, nIIV * nSubject), nrow = nIIV)) 151 | } 152 | 153 | ################################################################################ 154 | ################################################################################ 155 | 156 | ################################################################################ 157 | ################################# Run model #################################### 158 | ################################################################################ 159 | 160 | ## The Stan model 161 | modelFile <- file.path(modelDir, paste(modelName, ".stan", sep = "")) 162 | 163 | ## Run Stan 164 | nChains <- 4 165 | nPost <- 250 ## Number of post-burn-in samples per chain after thinning 166 | nBurn <- 250 ## Number of burn-in samples per chain after thinning 167 | nThin <- 1 168 | 169 | nIter <- (nPost + nBurn) * nThin 170 | nBurnin <- nBurn * nThin 171 | 172 | 173 | if(fitModel){ 174 | # create stan model object 175 | file.copy(file.path(modelDir, paste0(modelName, ".stan")), 176 | file.path(outDir, paste0(modelName, ".stan")), overwrite = TRUE) 177 | 178 | mod <- cmdstan_model(file.path(outDir, paste0(modelName, ".stan"))) 179 | 180 | fit <- mod$sample(data = data, chains = nChains, init = init, 181 | parallel_chains = nChains, 182 | iter_warmup = nBurn, iter_sampling = nPost, 183 | seed = sample(1:999999, 1), adapt_delta = 0.8, 184 | refresh = 10, 185 | output_dir = outDir) 186 | 187 | fit$save_object(file.path(outDir, paste0(modelName, ".fit.RDS"))) 188 | }else{ 189 | fit <- readRDS(file.path(outDir, paste0(modelName, ".fit.RDS"))) 190 | } 191 | 192 | ################################################################################ 193 | ################################################################################ 194 | 195 | ################################################################################ 196 | ################################## Analysis #################################### 197 | ################################################################################ 198 | 199 | if(runAnalysis){ 200 | 201 | # load fit object 202 | fit <- readRDS(file.path(outDir, paste0(modelName, ".fit.RDS"))) 203 | 204 | ## Specify the variables for which you want history and density plots 205 | parametersToPlot <- c("CLintHat", "KbBR", "KbMU", "KbAD", "KbBO", "KbRB", 206 | "sigma", "omega", "rho") 207 | 208 | ## Additional variables to monitor 209 | otherRVs <- c("cObsCond", "cObsPred", 210 | "cHat") 211 | 212 | parameters <- c(parametersToPlot, otherRVs) 213 | 214 | # set theme for plots 215 | myTheme <- theme(text = element_text(size = 12), axis.text = element_text(size = 12)) 216 | 217 | parametersToPlot <- setdiff(parametersToPlot, "rho") 218 | subset.pars <- subset_draws(fit$draws(), variable=parametersToPlot) 219 | 220 | ## diagnostics ## 221 | # summary 222 | # fitSumm <- fit$summary() # this will grab all model outputs 223 | fitSummParams <- fit$summary(variables = parametersToPlot) 224 | write.csv(fitSummParams, file = file.path(tabDir, paste(modelName, "ParameterTable.csv", sep = "-")), quote = F, row.names = F) 225 | 226 | # density 227 | plot_mcmcDensityByChain <- mcmc_dens_overlay(subset.pars, facet_args=list(ncol=2))+facet_text(size=10)+theme(axis.text=element_text(size=10)) 228 | plot_mcmcDensity <- mcmc_dens(subset.pars, facet_args=list(ncol=4))+facet_text(size=10)+theme(axis.text=element_text(size=10)) 229 | 230 | # rhat 231 | rhats <- bayesplot::rhat(fit, pars = parametersToPlot) 232 | plot_rhat <- mcmc_rhat(rhats) + yaxis_text() + myTheme 233 | 234 | # neff 235 | ratios1 <- bayesplot::neff_ratio(fit, pars = parametersToPlot) 236 | plot_neff <- mcmc_neff(ratios1) + yaxis_text() + myTheme 237 | 238 | # history 239 | draws_array <- fit$draws() 240 | plot_mcmcHistory <- mcmc_trace(draws_array, pars = c(parametersToPlot[1:7], "omega[1]"), facet_args = list(ncol = 2)) 241 | 242 | # correlation 243 | plot_pairs <- mcmc_pairs(draws_array, pars = c(parametersToPlot[1:7], "omega[1]"), off_diag_args = list(size = 1.5), diag_fun = "dens") 244 | 245 | # join history and densities 246 | plot_historyDensity <- plot_grid(plot_mcmcHistory, plot_mcmcDensityByChain, ncol = 2, labels = c("A","B")) 247 | 248 | # save 249 | plotFile <- mrggsave(list(plot_rhat, 250 | plot_neff, 251 | plot_mcmcHistory, 252 | plot_mcmcDensityByChain, 253 | plot_mcmcDensity, 254 | plot_historyDensity), 255 | scriptName, 256 | dir = figDir, stem = paste(modelName, "MCMCDiagnostics", sep = "-"), 257 | width = 10, height = 8, 258 | onefile = TRUE) 259 | 260 | plotFile_pairs <- mrggsave(list(plot_pairs), 261 | scriptName, 262 | dir = figDir, stem = paste(modelName, "MCMCDiagnostics-Corrs", sep = "-"), 263 | width = 14, height = 14, 264 | onefile = TRUE) 265 | 266 | ############# 267 | 268 | ## predictive checks ## 269 | # get cobsPred and cobsCond 270 | cobsCond.rep <- as_draws_matrix(fit$draws(variables = c("cObsCond"))) 271 | cobsPred.rep <- as_draws_matrix(fit$draws(variables = c("cObsPred"))) 272 | 273 | time <- data[["time"]] 274 | nSubject <- data[["nSubject"]] 275 | nObs <- data[["nObs"]] 276 | iObs <- data[["iObs"]] 277 | cObs <- data[["cObs"]] 278 | nti <- data[["nti"]] 279 | recByID <- unlist(sapply(1:nSubject, function(i){rep(i, nti[i])})) 280 | obsByID <- recByID[iObs] 281 | 282 | # plot_ppc_cobsCond <- ppc_ribbon_grouped(y=data[["cObs"]], yrep=cobsCond.rep, x=time[iObs], 283 | # group=obsByID) + scale_x_continuous(name="Time (h)") + 284 | # scale_y_continuous(name="Mavoglurant concentration (ng/mL)", trans = "log10") + theme(axis.text=element_text(size=10)) 285 | # 286 | plot_ppc_cobsPred <- ppc_ribbon_grouped(y=data[["cObs"]], yrep=cobsPred.rep, x=time[iObs], 287 | group=obsByID) + scale_x_continuous(name="Time (h)") + 288 | scale_y_continuous(name="Mavoglurant concentration (ng/mL)", trans = "log10") + theme(axis.text=element_text(size=10)) 289 | 290 | # ppc summary plot 291 | # get observed data 292 | df_cobs <- tibble(ID = obsByID, 293 | time = time[iObs], 294 | obs = cObs) %>% 295 | left_join(dat %>% mutate(ID2 = ID, ID = dense_rank(ID)) %>% select(ID, ID2, DOSE), by = "ID") %>% 296 | distinct() %>% 297 | mutate(dnobs = obs/DOSE) 298 | 299 | # get predictions 300 | df_cobsCond <- as_tibble(t(cobsCond.rep)) %>% 301 | mutate(ID = obsByID, time = time[iObs]) %>% 302 | gather(sim, pred, -ID, -time) %>% 303 | mutate(sim = as.integer(gsub("V","",sim))) %>% 304 | select(sim, ID, time, pred) %>% 305 | left_join(df_cobs %>% select(ID, ID2, DOSE), by = "ID") %>% 306 | distinct() %>% 307 | mutate(dnpred = pred/DOSE) 308 | 309 | df_cobsPred <- as_tibble(t(cobsPred.rep)) %>% 310 | mutate(ID = obsByID, time = time[iObs]) %>% 311 | gather(sim, pred, -ID, -time) %>% 312 | mutate(sim = as.integer(gsub("V","",sim))) %>% 313 | select(sim, ID, time, pred) %>% 314 | left_join(df_cobs %>% mutate(ID2 = ID, ID = dense_rank(ID)) %>% select(ID, ID2, DOSE), by = "ID") %>% 315 | distinct() %>% 316 | mutate(dnpred = pred/DOSE) 317 | 318 | plot_ppc_cobsPred_summ_byDose <- vpc(sim = df_cobsPred, 319 | obs = df_cobs, # supply simulation and observation dataframes 320 | obs_cols = list( 321 | id = "ID2", 322 | dv = "obs", # these column names are the default, 323 | idv = "time"), # update these if different. 324 | sim_cols = list( 325 | id = "ID2", 326 | dv = "pred", 327 | idv = "time", 328 | sim = "sim"), 329 | stratify = "DOSE", 330 | bins = c(0, 2, 4, 6, 8, 10, 20, 30, 40, 50), # specify bin separators manually 331 | pi = c(0.05, 0.95), # prediction interval simulated data to show 332 | ci = c(0.025, 0.975), # confidence intervals to show 333 | pred_corr = FALSE, # perform prediction-correction? 334 | show = list(obs_dv = TRUE), # plot observations? 335 | ylab = "Mavoglurant concentration (ng/mL)", 336 | xlab = "Time (h)") + 337 | scale_y_continuous(trans = "log10") + theme_bw() + theme(legend.text = element_text(size = 15), 338 | axis.title = element_text(size = 15)) 339 | 340 | plot_ppc_cobsPred_summ_total <- vpc(sim = df_cobsPred, 341 | obs = df_cobs, # supply simulation and observation dataframes 342 | obs_cols = list( 343 | id = "ID2", 344 | dv = "obs", # these column names are the default, 345 | idv = "time"), # update these if different. 346 | sim_cols = list( 347 | id = "ID2", 348 | dv = "pred", 349 | idv = "time", 350 | sim = "sim"), 351 | bins = c(0, 2, 4, 6, 8, 10, 20, 30, 40, 50), # specify bin separators manually 352 | pi = c(0.05, 0.95), # prediction interval simulated data to show 353 | ci = c(0.025, 0.975), # confidence intervals to show 354 | pred_corr = FALSE, # perform prediction-correction? 355 | show = list(obs_dv = TRUE), # plot observations? 356 | ylab = "Mavoglurant concentration (ng/mL)", 357 | xlab = "Time (h)") + 358 | scale_y_continuous(trans = "log10") + theme_bw() + theme(legend.text = element_text(size = 15), 359 | axis.title = element_text(size = 15)) 360 | 361 | plot_ppc_cobsPred_summ_total_dosenorm <- vpc(sim = df_cobsPred, 362 | obs = df_cobs, # supply simulation and observation dataframes 363 | obs_cols = list( 364 | id = "ID2", 365 | dv = "dnobs", # these column names are the default, 366 | idv = "time"), # update these if different. 367 | sim_cols = list( 368 | id = "ID2", 369 | dv = "dnpred", 370 | idv = "time", 371 | sim = "sim"), 372 | bins = c(0, 2, 4, 6, 8, 10, 20, 30, 40, 50), # specify bin separators manually 373 | pi = c(0.05, 0.95), # prediction interval simulated data to show 374 | ci = c(0.025, 0.975), # confidence intervals to show 375 | pred_corr = FALSE, # perform prediction-correction? 376 | show = list(obs_dv = TRUE), # plot observations? 377 | ylab = "Mavoglurant dose-normalized concentration (ng/mL/mg)", 378 | xlab = "Time (h)") + 379 | scale_y_continuous(trans = "log10", limits = c(0.01,100)) + theme_bw() + theme(legend.text = element_text(size = 15), 380 | axis.title = element_text(size = 15)) 381 | 382 | # individual plots 383 | df_cobsAll <- df_cobsCond %>% 384 | rename(cCond = pred) %>% 385 | bind_cols(df_cobsPred %>% 386 | select(cPred = pred)) 387 | 388 | df_cobsAll_summ <- df_cobsAll %>% 389 | group_by(ID, time) %>% 390 | mutate(loCond = lo(cCond), 391 | medCond = med(cCond), 392 | hiCond = hi(cCond), 393 | loPred = lo(cPred), 394 | medPred = med(cPred), 395 | hiPred = hi(cPred)) %>% 396 | slice(1) %>% 397 | ungroup() 398 | 399 | # join with observed 400 | df_simobs <- bind_cols(df_cobsAll_summ, df_cobs %>% select(cObs = obs)) 401 | 402 | # plot 403 | plot_ind <- ggplot(data=df_simobs, aes(x=time)) + 404 | geom_point(aes(y=cObs)) + 405 | geom_line(aes(y=medCond, color="Individual")) + 406 | geom_ribbon(aes(ymin = loCond, ymax=hiCond, fill="Individual"), alpha=0.2) + 407 | geom_line(aes(y=medPred, color="Population")) + 408 | geom_ribbon(aes(ymin = loPred, ymax=hiPred, fill="Population"), alpha=0.2) + 409 | facet_wrap(~ID2, ncol = 5) + 410 | scale_y_continuous(trans="log10") + 411 | scale_color_manual(name="", values = c("Individual" = "red", "Population" = "blue")) + 412 | scale_fill_manual(name="", values = c("Individual" = "red", "Population" = "blue")) + 413 | labs(x="Time (h)", y="Mavoglurant concentration (ng/mL)") + 414 | theme_bw() + 415 | theme(legend.position = "top", 416 | legend.text = element_text(size = 15), 417 | axis.title = element_text(size = 15)) 418 | 419 | # save 420 | plotFile <- mrggsave(list(plot_ppc_cobsPred, 421 | plot_ppc_cobsPred_summ_total, 422 | plot_ppc_cobsPred_summ_total_dosenorm, 423 | plot_ppc_cobsPred_summ_byDose, 424 | plot_ind), 425 | scriptName, 426 | dir = figDir, stem = paste(modelName,"PPC", sep = "-"), 427 | onefile = TRUE, 428 | width=10, height=8) 429 | } 430 | -------------------------------------------------------------------------------- /script/mavoPBPKLinODE_run.jl: -------------------------------------------------------------------------------- 1 | #= 2 | Version: October 18, 2022 3 | 4 | Online supplement to the tutorial: 5 | 6 | Bayesian PBPK Modeling using R/Stan/Torsten and Julia/SciML/Turing.jl 7 | 8 | This script runs the Bayesian PBPK linear ODE modeling in Julia/SciML/Turing.jl 9 | =# 10 | 11 | # activate pkg environment and load libraries 12 | # libraries are referenced in the Project.toml file 13 | cd(@__DIR__) 14 | cd("..") 15 | using Pkg; Pkg.activate(".") 16 | using CSV, DataFramesMeta, Chain, Random 17 | using OrdinaryDiffEq, DiffEqCallbacks, Turing, Distributions, CategoricalArrays 18 | using GlobalSensitivity, QuadGK 19 | using Plots, StatsPlots, MCMCChains 20 | using ExponentialUtilities 21 | using LinearAlgebra 22 | using Gadfly 23 | import Cairo, Fontconfig 24 | 25 | # set seed for reproducibility 26 | Random.seed!(123) 27 | 28 | # set paths 29 | modDir = "model" 30 | modName = "mavoPBPKLinODE" 31 | tabDir = joinpath("deliv","table") 32 | figDir = joinpath("deliv","figure") 33 | modPath = mkpath(joinpath(modDir, string(modName, "_jl"))) 34 | figPath = mkpath(joinpath(figDir, string(modName, "_jl"))) 35 | tabPath = mkpath(joinpath(tabDir, string(modName, "_jl"))) 36 | 37 | # read mavoglurant Study A2121 data; we'll only use the first 20 subjects 38 | dat_orig = CSV.read("data/Mavoglurant_A2121_nmpk.csv", DataFrame) 39 | dat = dat_orig[dat_orig.ID .<= 812,:] 40 | dat_obs = dat[dat.MDV .== 0,:] # grab first 20 subjects ; remove missing obs 41 | 42 | # load model 43 | include(joinpath("..", modDir, string(modName, ".jl"))); 44 | 45 | # set simulation conditions 46 | nSubject = length(unique(dat.ID)) 47 | doses = dat.AMT[dat.EVID .== 1,:] 48 | rates = dat.RATE[dat.EVID .== 1,:] 49 | durs = doses ./ rates 50 | ncmt = 16 51 | #u0 = zeros(ncmt) 52 | tspan = (0.0,maximum(dat.TIME)) 53 | times = [] 54 | for i in unique(dat_obs.ID); push!(times, dat_obs.TIME[dat_obs.ID .== i]); end 55 | 56 | # fixed parameters 57 | wts = dat.WT[dat.EVID .== 1,:] 58 | VVBs = (5.62 .* wts ./ 100) ./ 1.040 # volume of venous blood 59 | BP = 0.61 # blood:plasma concentration ratio 60 | 61 | # callback function for infusion stopping via zeroing k₀ parameter at end of infusion 62 | function affect!(integrator) 63 | integrator.p[8] = integrator.p[8] == 0.0 64 | end 65 | cbs = [] 66 | for i in 1:length(unique(dat.ID)); push!(cbs, PresetTimeCallback([durs[i]], affect!)); end 67 | 68 | # params to be estimated 69 | CLint = exp(7.1) 70 | KbBR = exp(1.1); 71 | KbMU = exp(0.3); 72 | KbAD = exp(2); 73 | KbBO = exp(0.03); 74 | KbRB = exp(0.3); 75 | p = [CLint, KbBR, KbMU, KbAD, KbBO, KbRB, wts[1]] 76 | 77 | # define the ODE problem 78 | #prob = ODEProblem(PBPKODE!, u0, tspan, p) 79 | 80 | ####### 81 | 82 | ## Bayesian inference ## 83 | 84 | ## define Bayesian model function 85 | @model function fitPBPK(data, nSubject, rates, times, wts, VVBs, BP) # data should be a Vector 86 | # priors 87 | ## informative priors for fixed effects and semi-informative for random effects 88 | σ ~ truncated(Cauchy(0, 0.5), 0.0, Inf) # residual error 89 | ĈLint ~ LogNormal(7.1,0.25) # intrinsic clearance 90 | KbBR ~ LogNormal(1.1,0.25) # brain to plasma partition coefficient 91 | KbMU ~ LogNormal(0.3,0.25) # muscle to plasma partition coefficient 92 | KbAD ~ LogNormal(2.0,0.25) # adipose to plasma partition coefficient 93 | KbBO ~ LogNormal(0.03, 0.25) # bone to plasma partition coefficient 94 | KbRB ~ LogNormal(0.3, 0.25) # rest of body to plasma partition coefficient 95 | ω ~ truncated(Cauchy(0, 0.5), 0.0, 1.0) # intersubject variability SD 96 | ηᵢ ~ filldist(Normal(0.0, 1.0), nSubject) # individual ηs for random effects 97 | 98 | # individual params 99 | CLintᵢ = ĈLint .* exp.(ω .* ηᵢ) # non-centered parameterization 100 | 101 | # initialize compartments with same type as params 102 | u0_tmp = eltype(KbBR).(zeros(ncmt)) 103 | u0_tmp[15] = doses[1] 104 | rate_tmp = eltype(KbBR).(zeros(ncmt)) 105 | rate_tmp[15] = rates[1] 106 | p1 = [CLintᵢ[1], KbBR, KbMU, KbAD, KbBO, KbRB, wts[1]] 107 | K_1 = PBPK(p1) 108 | K1 = DiffEqArrayOperator(K_1) 109 | time_reset = times[1] .- durs[1] 110 | prob1 = ODEProblem(K1, u0_tmp, (time_reset[1], time_reset[end])) 111 | 112 | # get preds for first two records for ID 1 that were measured before EOI 113 | u12 = eltype(K1).(zeros(ncmt, 2)) 114 | u12 = K_1\ExponentialUtilities.expv_timestep(times[1][1:2], K1, rate_tmp) .- K1\rate_tmp 115 | 116 | # function to update ODE problem with newly sampled params 117 | u0_eoi = eltype(K1).(zeros(ncmt)) 118 | function prob_func(prob,i,repeat) 119 | rate_tmp[15] = rates[i] 120 | ps = [CLintᵢ[i], KbBR, KbMU, KbAD, KbBO, KbRB, wts[i]] 121 | K_ = PBPK(ps) 122 | K = DiffEqArrayOperator(K_) 123 | u0_eoi = K\ExponentialUtilities.expv(durs[i], K, rate_tmp) - K\rate_tmp 124 | time_reset = times[i] .- durs[i] 125 | tspan_reset = (time_reset[1], time_reset[end]) 126 | prob_tmp = ODEProblem(K, u0_eoi, tspan_reset, tstops=time_reset) 127 | return(prob_tmp) 128 | end 129 | 130 | # define an ensemble problem and simulate the population 131 | tmp_ensemble_prob = EnsembleProblem(prob1, prob_func=prob_func) 132 | # solving can be parallelized by replacing EnsembleSerial() with EnsembleThreads() but there is no need since chains will be parallelized later 133 | # and having nested parallelization might lead to non reproducible results 134 | tmp_ensemble_sol = solve(tmp_ensemble_prob, LinearExponential(), EnsembleSerial(), trajectories=nSubject) 135 | 136 | # calculate predicted plasma concentration for the population and append in a vector 137 | predicted = [] 138 | for i in 1:nSubject 139 | times_tmp = times[i] .- durs[i] 140 | idx = findall(x -> x in times_tmp, tmp_ensemble_sol[i].t) 141 | tmp_sol = Array(tmp_ensemble_sol[i])[15,idx] ./ (VVBs[i]*BP/1000.0) 142 | append!(predicted, tmp_sol) 143 | end 144 | 145 | predicted[1:2] = u12[15,:] ./ (VVBs[1]*BP/1000.0) 146 | 147 | # likelihood 148 | for i = 1:length(predicted) 149 | data[i] ~ LogNormal(log.(max(predicted[i], 1e-12)), σ) 150 | end 151 | end 152 | 153 | # define the Bayesian model object 154 | mod = fitPBPK(dat_obs.DV, nSubject, rates, times, wts, VVBs, BP) 155 | 156 | # sample ; caution: sampling might take several hours to finish 157 | # you can skip sampling and go directly to lines 176 and 177 to load saved samples 158 | ## sampling conditions 159 | nsampl = 250 160 | nchains = 4 161 | adapt_delta = .8 162 | 163 | ## sampling in serial 164 | #@time mcmcchains = sample(mod, NUTS(nsampl,adapt_delta), MCMCSerial(), nsampl, nchains) 165 | #@time mcmcchains_prior = sample(mod, Prior(), MCMCSerial(), nsampl, nchains) # parallel 166 | 167 | ## sampling with multithreading ; caution: results might not be reproducible 168 | @time mcmcchains = sample(mod, NUTS(nsampl,adapt_delta), MCMCThreads(), nsampl, nchains) 169 | @time mcmcchains_prior = sample(mod, Prior(), MCMCThreads(), nsampl, nchains) # parallel 170 | 171 | ## save mcmcchains; uncomment to save generated chains; caution: this will overwrite the already saved chains 172 | #write(joinpath(modPath, string(modName, "chains.jls")), mcmcchains) 173 | #write(joinpath(modPath, string(modName, "chains_prior.jls")), mcmcchains_prior) 174 | 175 | ##uncomment to load saved chains 176 | #mcmcchains = read(joinpath(modPath, string(modName, "chains.jls")), Chains) 177 | #mcmcchains_prior = read(joinpath(modPath, string(modName, "chains_prior.jls")), Chains) 178 | 179 | 180 | #---# diagnostics #---# 181 | # tables 182 | summ, quant = describe(mcmcchains) 183 | #summ, quant = describe(mcmcchains; q = [0.05, 0.25, 0.5, 0.75, 0.95]) # control quantiles in output 184 | 185 | ## summary 186 | df_summ = DataFrame(summ) 187 | CSV.write(joinpath(tabPath, "Summary.csv"), df_summ) 188 | 189 | ## quantiles 190 | df_quant = DataFrame(quant) 191 | CSV.write(joinpath(tabPath, "Quantiles.csv"), df_quant) 192 | 193 | # plots 194 | ## trace plots ; we will split plots and join later for better view 195 | #plot_chains = StatsPlots.plot(mcmcchains[:,1:8,:]) # mcmcchains[samples, params, chains] 196 | plot_chains1 = StatsPlots.plot(mcmcchains[:,1:4,:]) 197 | plot_chains2 = StatsPlots.plot(mcmcchains[:,5:8,:]) 198 | plot_chains = Plots.plot(plot_chains1, plot_chains2, layout = (1,2)) 199 | savefig(plot_chains, joinpath(figPath, "MCMCTrace.pdf")) 200 | 201 | ## density plots 202 | p_post = zeros(nsampl, 8, 4) 203 | p_prior = deepcopy(p_post) 204 | 205 | for i in 1:4; p_post[:,:,i] = Array(mcmcchains[:,1:8,1]); end 206 | for i in 1:4; p_prior[:,:,i] = Array(mcmcchains_prior[:,1:8,1]); end 207 | 208 | p_post_mean = mean(p_post, dims=3)[:,:,1] 209 | p_prior_mean = mean(p_prior, dims=3)[:,:,1] 210 | 211 | pars = summ[1:8,1] 212 | dens_plots = [] 213 | for i in 1:8; p = density(p_post_mean[:,i], title=pars[i], label="Posterior"); density!(p_prior_mean[:,i], label="Prior"); push!(dens_plots, p); end 214 | 215 | dens_plots[1] = Plots.plot(dens_plots[1], xlims=(0.0,0.6)) 216 | 217 | plot_dens = Plots.plot(dens_plots[1], 218 | dens_plots[2], 219 | dens_plots[3], 220 | dens_plots[4], 221 | dens_plots[5], 222 | dens_plots[6], 223 | dens_plots[7], 224 | dens_plots[8], 225 | layout=grid(4,2), 226 | size = (650,650)) 227 | savefig(plot_dens, joinpath(figPath, "DensPlots.pdf")) 228 | 229 | #---# predictive checks #---# 230 | 231 | #= 232 | Predicitive checks can be conditioned on sampled parameters or on samples from a new population. 233 | Here, we will do both. 234 | =# 235 | 236 | #--# conditional on chains #--# 237 | 238 | # we will first create a vector of "missing" values to pass to the Bayesian fit function 239 | # Turing will understand that the created model object is meant to simulate rather than fit 240 | dat_missing = Vector{Missing}(missing, length(dat_obs.DV)) # vector of `missing` 241 | mod_pred = fitPBPK(dat_missing, nSubject, rates, times, wts, VVBs, BP) 242 | #pred = predict(mod_pred, mcmcchains) # posterior ; conditioned on each sample in chains 243 | pred = predict(mod_pred, mcmcchains, include_all=false) # include_all = false means sampling new !! 244 | #pred_prior = predict(mod_pred, mcmcchains_prior) 245 | 246 | ### predictive checks summaries 247 | #summarystats(pred) 248 | summ_pred, quant_pred = describe(pred) 249 | #summarystats(pred_prior) 250 | #summ_pred_prior, quant_pred_prior = describe(pred_prior) 251 | 252 | #### save 253 | #CSV.write(joinpath(tabPath, "Summary_PPC.csv"), summ_pred) 254 | #CSV.write(joinpath(tabPath, "Quantiles_PPC.csv"), quant_pred) 255 | 256 | # data assembly to summarise and bring observed and predicted data together 257 | bins = [0, 1, 2, 3, 4, 6, 8, 10, 20, 30, 40, 50] 258 | labels = string.(1:length(bins) - 1) 259 | 260 | ## observed 261 | df_vpc_obs = @chain begin 262 | dat_obs 263 | @select(:ID, :TIME, :DV, :DOSE) 264 | @transform(:DNDV = :DV ./ :DOSE, 265 | :bins = cut(:TIME, bins, labels = labels)) 266 | 267 | groupby(:bins) 268 | @transform(:lo = quantile(:DNDV, 0.05), 269 | :med = quantile(:DNDV, 0.5), 270 | :hi = quantile(:DNDV, 0.95)) 271 | end 272 | df_vpc_obs2 = @orderby(unique(@select(df_vpc_obs, :TIME, :bins, :lo, :med, :hi)), :TIME) 273 | 274 | ## predicted 275 | df_pred = DataFrame(pred) 276 | df_vpc_pred = @chain begin 277 | df_pred 278 | DataFramesMeta.stack(3:ncol(df_pred)) 279 | @orderby(:iteration, :chain) 280 | hcat(select(repeat(dat_obs, 1000), [:ID,:TIME,:DOSE])) 281 | @transform(:DNDV = :value ./ :DOSE, 282 | :bins = cut(:TIME, bins, labels = labels)) 283 | 284 | groupby([:iteration, :chain, :bins]) 285 | @transform(:lo = quantile(:DNDV, 0.05), 286 | :med = quantile(:DNDV, 0.5), 287 | :hi = quantile(:DNDV, 0.95)) 288 | 289 | groupby(:bins) 290 | @transform(:loLo = quantile(:lo, 0.025), 291 | :medLo = quantile(:lo, 0.5), 292 | :hiLo = quantile(:lo, 0.975), 293 | :loMed = quantile(:med, 0.025), 294 | :medMed = quantile(:med, 0.5), 295 | :hiMed = quantile(:med, 0.975), 296 | :loHi = quantile(:hi, 0.025), 297 | :medHi = quantile(:hi, 0.5), 298 | :hiHi = quantile(:hi, 0.975)) 299 | end 300 | 301 | df_vpc_pred2 = @orderby(unique(df_vpc_pred[!,[6;13:21]]), :TIME) 302 | 303 | ### plot 304 | dat_obs2 = @transform(dat_obs, :DNDV = :DV ./ :DOSE) 305 | 306 | set_default_plot_size(17cm, 12cm) 307 | 308 | plot_ppc = Gadfly.plot(x=dat_obs2.TIME, y=dat_obs2.DNDV, Geom.point, Scale.y_log10, Theme(background_color="white", default_color="black"), alpha=[0.2], Guide.xlabel("Time (h)"), Guide.ylabel("Mavoglurant dose-normalized concentration (ng/mL/mg)", orientation=:vertical), 309 | layer(x=df_vpc_obs.TIME, y=df_vpc_obs.med, Geom.line, Theme(default_color="black")), 310 | layer(x=df_vpc_obs.TIME, y=df_vpc_obs.lo, Geom.line, Theme(default_color="black")), 311 | layer(x=df_vpc_obs.TIME, y=df_vpc_obs.hi, Geom.line, Theme(default_color="black")), 312 | layer(x=df_vpc_pred2.TIME, ymin=df_vpc_pred2.loMed, ymax=df_vpc_pred2.hiMed, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.8]), 313 | layer(x=df_vpc_pred2.TIME, ymin=df_vpc_pred2.loLo, ymax=df_vpc_pred2.hiLo, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.5]), 314 | layer(x=df_vpc_pred2.TIME, ymin=df_vpc_pred2.loHi, ymax=df_vpc_pred2.hiHi, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.5])) 315 | 316 | plot_tmp = PDF(joinpath(figPath, "PPCCond.pdf"), 17cm, 12cm) 317 | draw(plot_tmp, plot_ppc) 318 | 319 | 320 | #--# new population #--# 321 | 322 | df_params = DataFrame(mcmcchains)[:,3:10] 323 | 324 | # save CSV 325 | #CSV.write(joinpath(modPath, "df_params.csv"), df_params) 326 | 327 | ## new etas for a new population 328 | ηs = reshape(rand(Normal(0.0, 1.0), nSubject*nrow(df_params)), nrow(df_params), nSubject) 329 | 330 | # run simulations for the new population 331 | array_pred = Array{Float64}(undef, nrow(df_params), nrow(dat_obs)) 332 | 333 | for j in 1:nrow(df_params) 334 | KbBR = df_params[j,:KbBR] 335 | KbMU = df_params[j,:KbMU] 336 | KbAD = df_params[j,:KbAD] 337 | KbBO = df_params[j,:KbBO] 338 | KbRB = df_params[j,:KbRB] 339 | 340 | CLintᵢ = df_params[j,:ĈLint] .* exp.(df_params[j,:ω] .* ηs[j,:]) 341 | 342 | # initialize compartments with same type as params 343 | u0_tmp = eltype(KbBR).(zeros(ncmt)) 344 | u0_tmp[15] = doses[1] 345 | rate_tmp = eltype(KbBR).(zeros(ncmt)) 346 | rate_tmp[15] = rates[1] 347 | p1 = [CLintᵢ[1], KbBR, KbMU, KbAD, KbBO, KbRB, wts[1]] 348 | K_1 = PBPK(p1) 349 | K1 = DiffEqArrayOperator(K_1) 350 | time_reset = times[1] .- durs[1] 351 | prob1 = ODEProblem(K1, u0_tmp, (time_reset[1], time_reset[end])) 352 | 353 | # get preds for first two records for ID 1 that were measured before EOI 354 | u12 = eltype(K1).(zeros(ncmt, 2)) 355 | u12 = K_1\ExponentialUtilities.expv_timestep(times[1][1:2], K1, rate_tmp) .- K1\rate_tmp 356 | 357 | # function to update ODE problem with newly sampled params 358 | u0_eoi = eltype(K1).(zeros(ncmt)) 359 | function prob_func(prob,i,repeat) 360 | rate_tmp[15] = rates[i] 361 | ps = [CLintᵢ[i], KbBR, KbMU, KbAD, KbBO, KbRB, wts[i]] 362 | K_ = PBPK(ps) 363 | K = DiffEqArrayOperator(K_) 364 | u0_eoi = K\ExponentialUtilities.expv(durs[i], K, rate_tmp) .- K\rate_tmp 365 | time_reset = times[i] .- durs[i] 366 | tspan_reset = (time_reset[1], time_reset[end]) 367 | prob_tmp = ODEProblem(K, u0_eoi, tspan_reset, tstops=time_reset) 368 | return(prob_tmp) 369 | end 370 | 371 | # define an ensemble problem and simulate the population 372 | tmp_ensemble_prob = EnsembleProblem(prob1, prob_func=prob_func) 373 | tmp_ensemble_sol = solve(tmp_ensemble_prob, LinearExponential(), EnsembleSerial(), trajectories=nSubject) 374 | 375 | predicted = [] 376 | for i in 1:nSubject 377 | times_tmp = times[i] .- durs[i] 378 | idx = findall(x -> x in times_tmp, tmp_ensemble_sol[i].t) 379 | tmp_sol = Array(tmp_ensemble_sol[i])[15,idx] ./ (VVBs[i]*BP/1000.0) 380 | append!(predicted, tmp_sol) 381 | end 382 | 383 | predicted[1:2] = u12[15,:] ./ (VVBs[1]*BP/1000.0) 384 | 385 | array_pred[j, :] = rand.(LogNormal.(log.(max.(predicted, 1e-12)), df_params[j,:σ])) 386 | end 387 | 388 | df_pred_new = DataFrame(array_pred, :auto) 389 | @transform!(df_pred_new, :iteration = 1:size(array_pred)[1]) 390 | 391 | # save version for R's vpc 392 | df_pred_new2 = @chain begin 393 | df_pred_new 394 | DataFramesMeta.stack(1:268) 395 | @orderby(:iteration) 396 | hcat(select(repeat(dat_obs, 1000), [:ID,:TIME,:DOSE])) 397 | @transform(:DNDV = :value ./ :DOSE) 398 | end 399 | 400 | # save CSV 401 | #CSV.write(joinpath(modPath, "df_pred.csv"), df_pred_new2) 402 | 403 | # create the new population predictions dataframe 404 | df_vpc_pred_new = @chain begin 405 | df_pred_new 406 | DataFramesMeta.stack(1:268) 407 | @orderby(:iteration) 408 | hcat(select(repeat(dat_obs, 1000), [:ID,:TIME,:DOSE])) 409 | @transform(:DNDV = :value ./ :DOSE, 410 | :bins = cut(:TIME, bins, labels = labels)) 411 | 412 | groupby([:iteration, :bins]) 413 | @transform(:lo = quantile(:DNDV, 0.05), 414 | :med = quantile(:DNDV, 0.5), 415 | :hi = quantile(:DNDV, 0.95)) 416 | 417 | groupby(:bins) 418 | @transform(:loLo = quantile(:lo, 0.025), 419 | :medLo = quantile(:lo, 0.5), 420 | :hiLo = quantile(:lo, 0.975), 421 | :loMed = quantile(:med, 0.025), 422 | :medMed = quantile(:med, 0.5), 423 | :hiMed = quantile(:med, 0.975), 424 | :loHi = quantile(:hi, 0.025), 425 | :medHi = quantile(:hi, 0.5), 426 | :hiHi = quantile(:hi, 0.975)) 427 | end 428 | 429 | df_vpc_pred_new2 = @orderby(unique(df_vpc_pred_new[!,[5;12:20]]), :TIME) 430 | 431 | ### plot 432 | #dat_obs2 = @transform(dat_obs, :DNDV = :DV ./ :DOSE) 433 | 434 | set_default_plot_size(17cm, 12cm) 435 | 436 | plot_ppc_new = Gadfly.plot(x=dat_obs2.TIME, y=dat_obs2.DNDV, Geom.point, Scale.y_log10, Theme(background_color="white", default_color="black"), alpha=[0.2], Guide.xlabel("Time (h)"), Guide.ylabel("Mavoglurant dose-normalized concentration (ng/mL/mg)", orientation=:vertical), 437 | layer(x=df_vpc_obs.TIME, y=df_vpc_obs.med, Geom.line, Theme(default_color="black")), 438 | layer(x=df_vpc_obs.TIME, y=df_vpc_obs.lo, Geom.line, Theme(default_color="black")), 439 | layer(x=df_vpc_obs.TIME, y=df_vpc_obs.hi, Geom.line, Theme(default_color="black")), 440 | layer(x=df_vpc_pred_new2.TIME, ymin=df_vpc_pred_new2.loMed, ymax=df_vpc_pred_new2.hiMed, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.8]), 441 | layer(x=df_vpc_pred_new2.TIME, ymin=df_vpc_pred_new2.loLo, ymax=df_vpc_pred_new2.hiLo, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.5]), 442 | layer(x=df_vpc_pred_new2.TIME, ymin=df_vpc_pred_new2.loHi, ymax=df_vpc_pred_new2.hiHi, Geom.ribbon, Theme(default_color="deepskyblue"), alpha=[0.5])) 443 | 444 | plot_tmp = PDF(joinpath(figPath, "PPCPred.pdf"), 17cm, 12cm) 445 | draw(plot_tmp, plot_ppc_new) 446 | 447 | #--# individual plots #--# 448 | 449 | df_cObs = @chain begin 450 | df_vpc_obs 451 | @select(:ID,:TIME,:DV,:DOSE) 452 | end 453 | 454 | # conditioned on individual data 455 | df_cCond = @chain begin 456 | df_vpc_pred 457 | groupby([:ID,:TIME]) 458 | @transform(:loCond = quantile(:value, 0.05), 459 | :medCond = quantile(:value, 0.5), 460 | :hiCond = quantile(:value, 0.95)) 461 | @select(:ID, :TIME, :DOSE, :loCond, :medCond, :hiCond) 462 | unique() 463 | end 464 | 465 | # conditioned on individuals in a new population 466 | df_cPred = @chain begin 467 | df_vpc_pred_new 468 | groupby([:ID,:TIME]) 469 | @transform(:loPred = quantile(:value, 0.05), 470 | :medPred = quantile(:value, 0.5), 471 | :hiPred = quantile(:value, 0.95)) 472 | @select(:ID, :TIME, :DOSE, :loPred, :medPred, :hiPred) 473 | unique() 474 | end 475 | 476 | # join all data 477 | df_cAll = hcat(df_cObs, 478 | @select(df_cCond, :loCond, :medCond, :hiCond), 479 | @select(df_cPred, :loPred, :medPred, :hiPred)) 480 | 481 | # save CSV for plotting in R 482 | CSV.write(joinpath(modPath, "df_ind.csv"), df_cAll) 483 | 484 | 485 | 486 | 487 | 488 | -------------------------------------------------------------------------------- /script/tools/cmdStanTools.R: -------------------------------------------------------------------------------- 1 | ## 5/27/2016: v1.0 2 | 3 | ## functions to run cmdStan 4 | 5 | compileModelOld <- function(model, stanDir = stanDir){ 6 | modelName <- basename(model) 7 | dir.create(model) 8 | file.copy(paste(model, "stan", sep = "."), file.path(model, paste(modelName, "stan", sep = ".")), 9 | overwrite = TRUE) 10 | model <- file.path(model, modelName) 11 | system(paste("make --directory=", stanDir, " ", model, sep = "")) 12 | } 13 | 14 | compileModel <- function(model, stanDir = stanDir){ 15 | system(paste0("make --directory=", stanDir, " ", model)) 16 | } 17 | 18 | compileModelMPI <- function(model, stanDir = stanDir, nslaves = 2){ 19 | system(paste0("make clean-all; ", "make --directory=", stanDir, " -j", nslaves, " ", model)) 20 | } 21 | 22 | runModelOld <- function(model, data, iter, warmup, thin, init, seed, chain = 1, 23 | stepsize = 1, adapt_delta = 0.8, max_depth = 10, refresh = 100, tag=NULL){ 24 | modelName <- basename(model) 25 | model <- file.path(model, modelName) 26 | if(! is.null(tag)) output <- paste0(model, "_", tag, "_") else output=model 27 | system(paste(model, " sample algorithm=hmc engine=nuts", 28 | " max_depth=", max_depth, 29 | " stepsize=", stepsize, 30 | " num_samples=", iter - warmup, 31 | " num_warmup=", warmup, " thin=", thin, 32 | " adapt delta=", adapt_delta, 33 | " data file=", data, 34 | " init=", init, " random seed=", seed, 35 | " output file=", paste(output, chain, ".csv", sep = ""), 36 | " refresh=", refresh, 37 | sep = "")) 38 | } 39 | 40 | runModel <- function(model, data, iter, warmup, thin, init, seed, chain = 1, 41 | stepsize = 1, adapt_delta = 0.8, max_depth = 10, refresh = 100, tag=NULL){ 42 | if(! is.null(tag)) output <- paste0(model, "_", tag, "_") else output=model 43 | system(paste(model, " sample algorithm=hmc engine=nuts", 44 | " max_depth=", max_depth, 45 | " stepsize=", stepsize, 46 | " num_samples=", iter - warmup, 47 | " num_warmup=", warmup, " thin=", thin, 48 | " adapt delta=", adapt_delta, 49 | " data file=", data, 50 | " init=", init, " random seed=", seed, 51 | " output file=", paste(output, chain, ".csv", sep = ""), 52 | " refresh=", refresh, 53 | sep = "")) 54 | } 55 | 56 | runModelMPI <- function(model, data, iter, warmup, thin, init, seed, chain = 1, 57 | stepsize = 1, adapt_delta = 0.8, max_depth = 10, refresh = 20, 58 | save_warmup = 0, tag=NULL, 59 | nslaves = 2){ 60 | if(! is.null(tag)) output <- paste0(model, "_", tag, "_") else output=model 61 | system(paste("mpiexec -n ", nslaves, " -l ", model, " sample algorithm=hmc engine=nuts", 62 | " max_depth=", max_depth, 63 | " stepsize=", stepsize, 64 | " num_samples=", iter - warmup, 65 | " num_warmup=", warmup, " thin=", thin, 66 | " save_warmup=", save_warmup, 67 | " adapt delta=", adapt_delta, 68 | " data file=", data, 69 | " init=", init, " random seed=", seed, 70 | " output file=", paste(output, chain, ".csv", sep = ""), 71 | " refresh=", refresh, 72 | sep = "")) 73 | } 74 | 75 | runDiagnose <- function(model, data, init, seed, chain = 1, refresh=100){ 76 | modelName <- basename(model) 77 | model <- file.path(model, modelName) 78 | system(paste(model, " diagnose", 79 | " data file=", data, 80 | " init=", init, " random seed=", seed, 81 | " output file=", paste(model, chain, ".csv", sep = ""), 82 | " refresh=", refresh, 83 | sep = "")) 84 | } 85 | 86 | # runModelFixed <- function(model, data, iter, warmup, thin, init, seed, chain = 1, 87 | # stepsize = 1, adapt_delta = 0.8, max_depth = 10, refresh = 100){ 88 | # modelName <- basename(model) 89 | # model <- file.path(model, modelName) 90 | # system(paste(model, " sample algorithm=fixed_param", 91 | # " num_samples=", iter, 92 | # " data file=", data, 93 | # " random seed=", seed, 94 | # " output file=", paste(model, chain, ".csv", sep = ""), 95 | # " refresh=", refresh, 96 | # sep = ""), invisible = FALSE) 97 | # } 98 | 99 | # runModelFixed <- function(model, data, iter, warmup, thin, init, seed, chain = 1, 100 | # stepsize = 1, adapt_delt = 0.8, max_depth = 10, refresh = 100){ 101 | # modelName <- basename(model) 102 | # model <- file.path(model, modelName) 103 | # print(paste0(model, " sample algorithm=fixed_param", 104 | # " num_samples=1 num_warmup=0", 105 | # " data file=", data, 106 | # " random seed=", seed, 107 | # " output file=", paste(model, chain, ".csv", sep = ""), 108 | # " refresh=", refresh)) 109 | # 110 | # system(paste0(model, " sample algorithm=fixed_param", 111 | # " num_samples=1 num_warmup=0", 112 | # " data file=", data, 113 | # " init=", init, 114 | # " random seed=", seed, 115 | # " output file=", paste(model, chain, ".csv", sep = ""), 116 | # " refresh=", refresh), invisible = FALSE) 117 | # 118 | # } 119 | 120 | runModelFixed <- function(model, data, iter, warmup, thin, init, seed, chain = 1, 121 | stepsize = 1, adapt_delta = 0.8, max_depth = 10, refresh = 100){ 122 | modelName <- basename(model) 123 | model <- file.path(model, modelName) 124 | system(paste(model, " sample algorithm=fixed_param", 125 | " num_samples=", iter, 126 | " data file=", data, 127 | " random seed=", seed, 128 | " output file=", paste(model, chain, ".csv", sep = ""), 129 | " refresh=", refresh, 130 | sep = ""), invisible = FALSE) 131 | } 132 | 133 | -------------------------------------------------------------------------------- /script/tools/functions.R: -------------------------------------------------------------------------------- 1 | ## Miscellaneous functions 2 | 3 | trapez = function(x,y){ 4 | nx = length(x) 5 | 0.5*sum((y[-1]+y[-nx])*(x[-1]-x[-nx])) 6 | } 7 | 8 | pkpar = function(x,y){ 9 | nx = length(x) 10 | auc = sum((x[-1]-x[-nx])*(y[-1]+y[-nx]),na.rm=T)/2 11 | nmax = order(y,na.last=F)[nx] 12 | cmax = y[nmax] 13 | tmax = x[nmax] 14 | c(auc=auc,cmax=cmax,tmax=tmax) 15 | } 16 | 17 | frac = function(x) sum(x)/length(x) 18 | 19 | swap = function(x, oldval, newval) 20 | { 21 | if(length(oldval) != length(newval)) 22 | stop("length(oldval)!=length(newval)") 23 | x1 = match(x, oldval, 0) 24 | x[as.logical(x1)] = newval[x1] 25 | x 26 | } 27 | 28 | mvdnorm = function(y,mu,sigma2){ 29 | # bivariate norma density 30 | d = length(mu) 31 | det.sigma2 = det(sigma2) 32 | inv.sigma2 = solve(sigma2) 33 | exp(-t(y-mu)%*%inv.sigma2%*%(y-mu)/2)/sqrt(((2*pi)^d)*det.sigma2) 34 | } 35 | 36 | 37 | # generalized logit and inverse logit functions 38 | logit.inv = function(x, lower = 0, upper = 1) 39 | { 40 | x1 <- exp(x) 41 | ifelse(is.infinite(x1),upper,lower + ((upper - lower) * x1)/(1 + x1)) 42 | } 43 | 44 | logit = function(x, lower = 0, upper = 1) 45 | { 46 | x <- (x - lower)/(upper - lower) 47 | log(x/(1 - x)) 48 | } 49 | 50 | factor2char.data.frame = function(x){ 51 | for(i in 1:ncol(x)){ 52 | if(class(x[[i]])=="factor") x[[i]] = as.character(x[[i]]) 53 | } 54 | x 55 | } 56 | 57 | strip.lead.blanks = function(x){ 58 | w = regexpr(" +",x) 59 | as.character(ifelse(w==1,substring(x,attr(w,"match.length")+1),x)) 60 | } 61 | 62 | symmat = function(a){ 63 | # generate symmetric matrix from its lower triangle given as 64 | # (a[1,1],a[2,1],a[2,2],a[3,1],a[3,2],a[3,3],...) 65 | n = (-1+sqrt(1+8*length(a)))/2 66 | x = matrix(rep(0,n*n),ncol=n) 67 | x[t(lower.tri(x,T))] = a 68 | y = x + t(t(lower.tri(x))*x) 69 | y 70 | } 71 | 72 | qqhist <- function(x, label = NULL, main=NULL) 73 | { 74 | # plot histogram and quantile-normal quantile plot for vector x 75 | 76 | plot1 <- histogram(~x, 77 | ylab=list(cex=1.2), xlab=list(label=label,cex=1.2), 78 | scales=list(cex=1.2)) 79 | plot2 <- qqmath(~x,prepanel = prepanel.qqmathline, 80 | panel=function(x){ 81 | panel.qqmath(x,cex=1.2,pch=16) 82 | panel.qqmathline(x,distribution=qnorm,col=3,lwd=3) 83 | }, 84 | ylab=list(label=label,cex=1.2), 85 | xlab=list(label="quantiles of standard normal",cex=1.2), 86 | scales=list(cex=1.2),ylim=range(x)) 87 | list(plot1=plot1,plot2=plot2) 88 | } 89 | 90 | qnorm.trunc = function(p,mean=0,sd=1,lower=-Inf,upper=Inf) 91 | qnorm(p*pnorm(upper,mean,sd)+(1-p)*pnorm(lower,mean,sd),mean,sd) 92 | 93 | rnorm.trunc = function(n,mean=0,sd=1,lower=-Inf,upper=Inf) 94 | qnorm.trunc(runif(n),mean,sd,lower,upper) 95 | 96 | # Prepanel and panel plot functions for error bars taken from R help response by 97 | # Deepayan Sarkar 98 | prepanel.ci <- function(y, ly, uy, subscripts, ...) 99 | { 100 | y <- as.numeric(y) 101 | ly <- as.numeric(ly[subscripts]) 102 | uy <- as.numeric(uy[subscripts]) 103 | list(ylim = range(y, uy, ly, finite = TRUE)) 104 | } 105 | 106 | panel.ci <- function(x, y, ly, uy, subscripts, pch = 16, col.line = 107 | 'black', ...) 108 | { 109 | x <- as.numeric(x) 110 | y <- as.numeric(y) 111 | ly <- as.numeric(ly[subscripts]) 112 | uy <- as.numeric(uy[subscripts]) 113 | panel.arrows(x, ly, x, uy, col = col.line, 114 | length = 0.25, unit = "native", 115 | angle = 90, code = 3) 116 | panel.xyplot(x, y, pch = pch, col.line = col.line, ...) 117 | } 118 | 119 | mbmaPpcPlot <- function(data, x = "x", treatment = "treatment", type = "type", xlab = "x"){ 120 | 121 | names(data)[names(data) == x] <- "x" 122 | names(data)[names(data) == treatment] <- "treatment" 123 | names(data)[names(data) == type] <- "type" 124 | xobs <- data[data$type == "observed",] 125 | 126 | ## Reorder assuming that the predicted values are in the same order as the observed values. 127 | xOrder <- order(xobs$treatment, xobs$x) 128 | xOrder <- rep(xOrder, 4) + rep(0:3, ea = length(xOrder)) * length(xOrder) 129 | data <- data[xOrder,] 130 | xobs <- data[data$type == "observed",] 131 | 132 | ## Calculate number of treatments and number of arms of each treatment 133 | treats <- unique(xobs$treatment) 134 | nTreat <- length(treats) 135 | nPerTreat <- sapply(treats, function(treat, data) 136 | sum(data$treatment == treat), 137 | data = xobs) 138 | 139 | ## Calculate number of equally spaced positions on the y axis 140 | ny <- sum(nPerTreat) + nTreat - 1 141 | dy <- 1 / (ny - 1) 142 | y <- (1:ny) * dy 143 | 144 | ## Drop y positions between treatments to create gaps 145 | iSkip <- cumsum(nPerTreat[-nTreat]) + 1:(nTreat - 1) 146 | y <- y[-iSkip] 147 | 148 | ## Calculate label locations 149 | iStart <- c(1, 1 + cumsum(nPerTreat[-nTreat])) 150 | iEnd <- cumsum(nPerTreat) 151 | yLab <- (y[iStart] + y[iEnd]) / 2 152 | 153 | data$y <- rep(y, 4) 154 | xyplot(y ~ x, data, groups = type, panel = 155 | function(x, y, subscripts, groups, ...){ 156 | iObs <- (groups[subscripts] == "observed") 157 | iMed <- (groups[subscripts] == "median") 158 | i5 <- (groups[subscripts] == "5%ile") 159 | i95 <- (groups[subscripts] == "95%ile") 160 | panel.xyplot(x[iObs], y[iObs], pch = 19, col = "black", ...) 161 | panel.segments(x[iMed], y[iMed] - dy/2, x[iMed], y[iMed] + dy/2, 162 | col = "red", lwd = 2, ...) 163 | panel.segments(x[i5], y[iMed], x[i95], y[iMed], 164 | col = "blue", lwd = 2, ...) 165 | }, 166 | scales = list(cex = 1.2, y = list(at = yLab, labels = treats)), 167 | xlab = xlab, ylab = "") 168 | } 169 | 170 | rbeta2 <- function(n, mean, sd){ 171 | v <- sd^2 172 | alpha <- (mean * (1 - mean) / v - 1) * mean 173 | beta <- (1 / mean - 1) * alpha 174 | if(alpha <= 0 | beta <= 0) stop("ERROR in rbeta2: alpha <= 0 | beta <= 0") 175 | rbeta(n, alpha, beta) 176 | } 177 | 178 | rbeta2Scaled <- function(n, mean, sd, lower, upper){ 179 | dx <- upper - lower 180 | m <- (mean - lower) / dx 181 | s <- sd / dx 182 | if(m < 0 | m > 1) stop("ERROR in rbeta2Scaled: m < 0 | m > 1") 183 | rbeta2(n, m, s) * dx + lower 184 | } 185 | 186 | compileModel <- function(model, stanDir = stanDir){ 187 | modelName <- basename(model) 188 | dir.create(model) 189 | file.copy(paste(model, "stan", sep = "."), file.path(model, paste(modelName, "stan", sep = ".")), 190 | overwrite = TRUE) 191 | model <- file.path(model, modelName) 192 | system(paste("make --directory=", stanDir, " ", model, sep = "")) 193 | } 194 | 195 | runModel <- function(model, data, iter, warmup, thin, init, seed, chain = 1, 196 | stepsize = NULL, adapt_delta = NULL, refresh = 1, 197 | save_warmup = 0, algorithm = "hmc", engine = "nuts"){ 198 | modelName <- basename(model) 199 | model <- file.path(model, modelName) 200 | system(paste(model, " sample", 201 | " algorithm=", algorithm, 202 | ifelse(is.null(engine), "", paste(" engine=", engine, sep = "")), 203 | ifelse(is.null(stepsize), "", paste(" stepsize=", stepsize, sep = "")), 204 | " num_samples=", iter - warmup, 205 | " num_warmup=", warmup, 206 | " save_warmup=", save_warmup, 207 | " thin=", thin, 208 | ifelse(is.null(adapt_delta), "", paste(" adapt delta=", adapt_delta, sep = "")), 209 | " data file=", data, 210 | ifelse(is.null(init), "", paste(" init=", init, sep = "")), 211 | " random seed=", seed, 212 | " output file=", paste(model, chain, ".csv", sep = ""), 213 | " refresh=", refresh, 214 | sep = "")) 215 | } 216 | 217 | 218 | ## adding this here temporarily 219 | #####Tool for writing results to disk######### 220 | includegraphics <- function(file, 221 | caption=rep(NA,length(file)), 222 | label=rep(NA,length(file)), 223 | width=0.8, place="H", page=1) { 224 | # Wrap a graphics file in LaTex includegraphics text for tex document authoring 225 | 226 | # @param file file (with full path) containing graphics 227 | # @param caption vector of captions of the same length as `file` 228 | # @param label vector of tex style labels the same length as `file` 229 | # @param width fraction of textwidth to make included graphic 230 | # @param place where to place the float 231 | # @param page page of `file` to include 232 | # @return character vector, tex includegraphics wrapper 233 | stopifnot(all(length(file) == length(caption),length(file)==length(label))) 234 | 235 | for(i in seq_along(file)) { 236 | 237 | writeLines(paste0("\\begin{figure}[",place,"]\\centering")) 238 | writeLines(paste0("\\includegraphics[width=",width,"\\textwidth, 239 | page=",page,"]{",file[i],"}")) 240 | if(!is.na(caption[i])) writeLines(paste0("\\caption{",caption[i],"}")) 241 | if(!is.na(label[i])) writeLines(paste0("\\label{",label[i],"}")) 242 | writeLines("\\end{figure}") 243 | } 244 | return(invisible(NULL)) 245 | } 246 | 247 | 248 | ## stats functions 249 | med <- function(x) quantile(x, probs=c(0.5), na.rm=T) 250 | lo <- function(x) quantile(x, probs=c(0.05), na.rm=T) 251 | hi <- function(x) quantile(x, probs=c(0.95), na.rm=T) 252 | lo10 <- function(x) quantile(x, probs=c(0.1), na.rm=T) 253 | hi90 <- function(x) quantile(x, probs=c(0.9), na.rm=T) 254 | lo25 <- function(x) quantile(x, probs=c(0.25), na.rm=T) 255 | hi75 <- function(x) quantile(x, probs=c(0.75), na.rm=T) 256 | 257 | sig <- function(x) signif(x, digits = 3) 258 | 259 | -------------------------------------------------------------------------------- /script/tools/stanTools.R: -------------------------------------------------------------------------------- 1 | getSimsTable <- function(x, ...){ 2 | require(dplyr) 3 | nChains <- dim(x)[2] 4 | nPost <- dim(x)[1] 5 | x %>% 6 | as.data.frame(...) %>% 7 | mutate(chain = rep(1:nChains, ea = nPost), 8 | iteration = rep(1:nPost, nChains)) 9 | } 10 | 11 | mcmcHistoryOld <- function(fit, pars = names(fit), nParPerPage = 6){ 12 | require(dplyr) 13 | require(tidyr) 14 | require(ggplot2) 15 | simsTable <- getSimsTable(fit, pars = pars) 16 | posterior <- simsTable %>% 17 | gather(key = parameter, value = value, -chain, -iteration) 18 | 19 | parameters <- sort(unique(posterior$parameter)) 20 | nParameters <- length(parameters) 21 | nPages <- ceiling(nParameters / nParPerPage) 22 | parameters <- data.frame(parameter = parameters, 23 | page = sort(rep(1:nPages, length = nParameters)), 24 | stringsAsFactors = FALSE) 25 | posterior <- posterior %>% left_join(parameters) 26 | posterior$chain <- as.factor(posterior$chain) 27 | 28 | for(i in 1:nPages){ 29 | xplot <- subset(posterior, page == i) 30 | p1 <- ggplot(xplot, aes(x = iteration, y = value)) 31 | print(p1 + aes(color = chain) + geom_line() + 32 | labs(x = "iteration", y = "value") + 33 | theme(text = element_text(size = 12), axis.text = element_text(size = 12), 34 | legend.position = "none", strip.text = element_text(size = 8)) + 35 | facet_wrap(~ parameter, ncol = 1, scales = "free_y")) 36 | } 37 | NULL 38 | } 39 | 40 | mcmcHistory <- function(fit, pars = names(fit), nParPerPage = 6, myTheme = NULL){ 41 | require(tidyverse) 42 | require(bayesplot) 43 | posterior <- as.array(fit, pars = pars) 44 | pars <- dimnames(posterior)[[3]] 45 | pnuts <- nuts_params(fit) 46 | 47 | nPars <- length(pars) 48 | nPages <- ceiling(nPars / nParPerPage) 49 | parameters <- data.frame(parameter = pars, 50 | page = sort(rep(1:nPages, length = nPars)), 51 | stringsAsFactors = FALSE) 52 | 53 | for(i in 1:nPages){ 54 | posterior <- as.array(fit, pars = with(parameters, pars[page == i])) 55 | if(sum((pnuts %>% filter(Parameter == "divergent__"))$Value)){ 56 | print(mcmc_trace(posterior, 57 | np = pnuts, 58 | facet_args = list(ncol = 1, strip.position = "left")) + 59 | myTheme + 60 | scale_x_continuous(breaks = seq(0, nPost, len = 5))) 61 | 62 | }else{ 63 | print(mcmc_trace(posterior, 64 | facet_args = list(ncol = 1, strip.position = "left")) + 65 | myTheme + 66 | scale_x_continuous(breaks = seq(0, nPost, len = 5))) 67 | } 68 | } 69 | NULL 70 | } 71 | 72 | mcmcHistory2 <- function(fit, pars = names(fit), nParPerPage = 6, myTheme = NULL, 73 | chains = NULL){ 74 | require(tidyverse) 75 | require(bayesplot) 76 | posterior <- as.array(fit, pars = pars) 77 | pars <- dimnames(posterior)[[3]] 78 | if(is.null(chains)) chains = 1:dim(posterior)[2] 79 | pnuts <- nuts_params(fit) 80 | 81 | nPars <- length(pars) 82 | nPages <- ceiling(nPars / nParPerPage) 83 | parameters <- data.frame(parameter = pars, 84 | page = sort(rep(1:nPages, length = nPars)), 85 | stringsAsFactors = FALSE) 86 | 87 | lapply(1:nPages, 88 | function(i){ 89 | posterior <- as.array(fit, pars = with(parameters, pars[page == i]))[, chains,] 90 | if(sum((pnuts %>% filter(Parameter == "divergent__"))$Value)){ 91 | res <- mcmc_trace(posterior, 92 | np = pnuts, 93 | facet_args = list(ncol = 1, strip.position = "left")) + 94 | myTheme + 95 | scale_x_continuous(breaks = seq(0, nPost, len = 5)) 96 | 97 | }else{ 98 | res <- mcmc_trace(posterior, 99 | facet_args = list(ncol = 1, strip.position = "left")) + 100 | myTheme + 101 | scale_x_continuous(breaks = seq(0, nPost, len = 5)) 102 | } 103 | res 104 | } 105 | ) 106 | } 107 | 108 | mcmcDensityOld <- function(fit, pars = names(fit), byChain = FALSE, nParPerPage = 16, prior = NULL){ 109 | require(dplyr) 110 | require(tidyr) 111 | require(ggplot2) 112 | simsTable <- getSimsTable(fit, pars = pars) 113 | posterior <- simsTable %>% 114 | gather(key = parameter, value = value, -chain, -iteration) 115 | simsTable <- getSimsTable(fit, pars = pars) 116 | 117 | parameters <- sort(unique(posterior$parameter)) 118 | nParameters <- length(parameters) 119 | nPages <- ceiling(nParameters / nParPerPage) 120 | parameters <- data.frame(parameter = parameters, 121 | page = sort(rep(1:nPages, length = nParameters)), 122 | stringsAsFactors = FALSE) 123 | posterior <- posterior %>% left_join(parameters) 124 | posterior$chain <- as.factor(posterior$chain) 125 | 126 | if(!is.null(prior)) prior <- prior %>% left_join(parameters) 127 | 128 | for(i in 1:nPages){ 129 | xplot <- subset(posterior, page == i) 130 | p1 <- ggplot(xplot, aes(x = value)) 131 | if(byChain) p1 <- p1 + aes(color = chain) 132 | p1 <- p1 + geom_density() + 133 | labs(x = "value", y = "density") + 134 | theme(text = element_text(size = 12), axis.text = element_text(size = 8), 135 | legend.position = "none", strip.text = element_text(size = 8)) + 136 | facet_wrap(~ parameter, ncol = 4, nrow = 4, scales = "free") 137 | if(!is.null(prior)) 138 | p1 <- p1 + geom_line(data = subset(prior, page == i), aes(x = value, y = density), 139 | color = "red") 140 | print(p1) 141 | } 142 | NULL 143 | } 144 | 145 | mcmcDensity2 <- function(fit, pars = names(fit), byChain = FALSE, nParPerPage = 16, 146 | myTheme = NULL, prior = NULL, chains = NULL){ 147 | require(tidyverse) 148 | require(bayesplot) 149 | posterior <- as.array(fit, pars = pars) 150 | pars <- dimnames(posterior)[[3]] 151 | if(is.null(chains)) chains = 1:dim(posterior)[2] 152 | 153 | nPars <- length(pars) 154 | nPages <- ceiling(nPars / nParPerPage) 155 | parameters <- data.frame(Parameter = pars, 156 | page = sort(rep(1:nPages, length = nPars)), 157 | stringsAsFactors = FALSE) 158 | 159 | if(!is.null(prior)) prior <- prior %>% left_join(parameters) 160 | 161 | lapply(1:nPages, 162 | function(i){ 163 | posterior <- as.array(fit, pars = with(parameters, pars[page == i]))[, chains,] 164 | if(byChain){ 165 | p1 <- mcmc_dens_overlay(posterior) 166 | }else{ 167 | p1 <- mcmc_dens(posterior) 168 | } 169 | if(!is.null(prior)) 170 | p1 <- p1 + geom_line(data = subset(prior, page == i), 171 | aes(x = value, y = density), 172 | color = "red") 173 | p1 + myTheme 174 | }) 175 | } 176 | 177 | mcmcDensity <- function(fit, pars = names(fit), byChain = FALSE, nParPerPage = 16, 178 | myTheme = NULL, prior = NULL){ 179 | require(tidyverse) 180 | require(bayesplot) 181 | posterior <- as.array(fit, pars = pars) 182 | pars <- dimnames(posterior)[[3]] 183 | pnuts <- nuts_params(fit) 184 | 185 | nPars <- length(pars) 186 | nPages <- ceiling(nPars / nParPerPage) 187 | parameters <- data.frame(Parameter = pars, 188 | page = sort(rep(1:nPages, length = nPars)), 189 | stringsAsFactors = FALSE) 190 | 191 | if(!is.null(prior)) prior <- prior %>% left_join(parameters) 192 | 193 | for(i in 1:nPages){ 194 | posterior <- as.array(fit, pars = with(parameters, pars[page == i])) 195 | if(byChain){ 196 | p1 <- mcmc_dens_overlay(posterior) 197 | }else{ 198 | p1 <- mcmc_dens(posterior) 199 | } 200 | if(!is.null(prior)) 201 | p1 <- p1 + geom_line(data = subset(prior, page == i), 202 | aes(x = value, y = density), 203 | color = "red") 204 | print(p1 + myTheme) 205 | } 206 | NULL 207 | } 208 | 209 | # summary.mcmc.list <- function (object, quantiles = c(0.025, 0.25, 0.5, 0.75, 0.975), 210 | # ...) 211 | # { 212 | # x <- mcmc.list(object) 213 | # statnames <- c("Mean", "SD", "Naive SE", "Time-series SE") 214 | # varstats <- matrix(nrow = nvar(x), ncol = length(statnames), 215 | # dimnames = list(varnames(x), statnames)) 216 | # xtsvar <- matrix(nrow = nchain(x), ncol = nvar(x)) 217 | # if (is.matrix(x[[1]])) { 218 | # for (i in 1:nchain(x)) for (j in 1:nvar(x)) xtsvar[i, 219 | # j] <- coda:::safespec0(x[[i]][, j]) 220 | # xlong <- do.call("rbind", x) 221 | # } 222 | # else { 223 | # for (i in 1:nchain(x)) xtsvar[i, ] <- coda:::safespec0(x[[i]]) 224 | # xlong <- as.matrix(x) 225 | # } 226 | # xmean <- apply(xlong, 2, mean, na.rm = TRUE) 227 | # xvar <- apply(xlong, 2, var, na.rm = TRUE) 228 | # xtsvar <- apply(xtsvar, 2, mean, na.rm = TRUE) 229 | # varquant <- t(apply(xlong, 2, quantile, quantiles, na.rm = TRUE)) 230 | # varstats[, 1] <- xmean 231 | # varstats[, 2] <- sqrt(xvar) 232 | # varstats[, 3] <- sqrt(xvar/(niter(x) * nchain(x))) 233 | # varstats[, 4] <- sqrt(xtsvar/(niter(x) * nchain(x))) 234 | # varquant <- drop(varquant) 235 | # varstats <- drop(varstats) 236 | # out <- list(statistics = varstats, quantiles = varquant, 237 | # start = start(x), end = end(x), thin = thin(x), nchain = nchain(x)) 238 | # class(out) <- "summary.mcmc" 239 | # return(out) 240 | # } 241 | 242 | parameterTable <- function(fit, pars = names(fit), chains = NULL){ 243 | posterior <- as.array(fit, pars = pars) 244 | if(!is.null(chains)) posterior <- posterior[, chains,] 245 | rstan:::monitor(posterior, warmup = 0, print = FALSE) 246 | } 247 | 248 | colVars <- function(a) { 249 | vars <- a[1,] 250 | for (n in 1:ncol(a)) 251 | vars[n] <- var(a[,n]) 252 | return(vars) 253 | } 254 | 255 | rhat <- function(fit, pars = names(fit), chains = NULL){ 256 | posterior <- as.array(fit, pars = pars) 257 | if(!is.null(chains)) posterior <- posterior[, chains,] 258 | rstan:::monitor(posterior, warmup = 0, print = FALSE)[, "Rhat"] 259 | } 260 | 261 | neff_ratio <- function(fit, pars = names(fit), chains = NULL){ 262 | posterior <- as.array(fit, pars = pars) 263 | if(!is.null(chains)) posterior <- posterior[, chains,] 264 | rstan:::monitor(posterior, warmup = 0, print = FALSE)[, "n_eff"] / 265 | (dim(posterior)[1] * dim(posterior)[2]) 266 | } 267 | 268 | --------------------------------------------------------------------------------