Skip to content

jam-sudo/Sisyphus

Repository files navigation

Sisyphus

Graph-based whole-body PBPK simulation with native uncertainty propagation

Methodology · Quickstart · Validation · Architecture · Limitations


Sisyphus is a physiologically based pharmacokinetic (PBPK) platform that represents the human body as a typed directed multi-graph, derives ordinary differential equation (ODE) systems from graph topology, and propagates parameter uncertainty natively through Monte Carlo sampling.

The platform accepts a SMILES string and dosing regimen as input and produces PK endpoints (Cmax, Tmax, AUC, t1/2) with 90% prediction intervals. Beyond single-dose prediction, Sisyphus supports multi-dose regimen simulation with steady-state detection, Bayesian therapeutic drug monitoring (TDM) via importance sampling, model-informed precision dosing (MIPD), drug-drug interaction (DDI) modeling, and PK/PD effect estimation.

$ sisyphus predict --smiles "Cn1c(=O)c2c(ncn2C)n(C)c1=O" --dose 100

Drug: Cn1c(=O)c2c(ncn2C)n(C)c1=O
Method: hybrid
Confidence: high
Cmax: 1.5247 mg/L
Tmax: 0.96 h
t½: 4.32 h

Methodology

Physiological model

The body is represented as a 34-compartment directed multi-graph comprising blood pools (arterial, venous, portal vein), perfusion-limited organs (11), permeability-limited organs (4, each split into vascular and extravascular sub-compartments), GI lumen segments (8, compartmental absorption and transit model; Yu & Amidon, 1999), and mass-balance sinks (4). Physiological parameters follow the ICRP Reference Man (ICRP, 2002). Tissue compositions for partition coefficient estimation are taken from Rodgers & Rowland (2005). CYP enzyme abundances follow Shimada et al. (1994).

                      ┌─────────────────────────────────────────────┐
                      │                                             │
   ┌──────┐    ┌──────┴───┐                                   ┌─────┴────┐
   │ lung │───►│ arterial │─► brain ─────────────────────────►│ venous   │
   └──┬───┘    │  blood   │─► heart ─────────────────────────►│  blood   │
      │        │          │─► kidney ────────────────────────►│          │
      │        │          │                                   │          │
      │        │          │─► gut wall ──┐                    │          │
      │        │          │─► spleen  ───┤ portal ► liver ───►│          │
      │        │          │─► pancreas ──┘  vein   (CYP450)   │          │
      │        │          │                                   │          │
      │        │          │─► muscle, adipose, skin, bone ───►│          │
      │        └──────────┘                                   └─────┬────┘
      │                                                             │
      └─────────────────────────────────────────────────────────────┘

   stomach ──► duodenum ──► jejunum ──► ileum ──► colon ──► fecal excretion
                  │            │          │
                  └────────────┴──────────┘
                       absorption ──► gut wall

ODE formulation

The ODE system is derived automatically from graph topology. Each edge type dispatches a flux function:

Perfusion-limited transport (FlowFluxSpec):

$$\frac{dA_i}{dt} = Q_i \cdot C_{in} - Q_i \cdot \frac{A_i \cdot R_{B:P}}{V_i \cdot K_{p,i}}$$

Well-stirred hepatic clearance (ClearanceFluxSpec):

$$CL_{int,organ} = \sum_j \left( E_j \cdot k_j \right) \cdot S_{IVIVE}$$

$$CL_{organ} = \frac{Q \cdot f_u \cdot CL_{int,organ}}{Q + f_u \cdot CL_{int,organ}}$$

where $E_j$ is the enzyme abundance (total pmol in organ), $k_j$ is the per-enzyme intrinsic clearance (μL/min/pmol), and $S_{IVIVE}$ converts units (60/106, μL/min → L/h). This formulation is enzyme-level: clearance at any organ is computed from its local enzyme profile, not from organ identity (Houston, 1994; Yang et al., 2007).

Permeability-limited distribution (DiffusionFluxSpec):

$$\frac{dA_{vasc}}{dt} = Q \cdot C_{art} - Q \cdot C_{vasc} - PS \cdot (C_{u,vasc} - C_{u,tissue})$$

$$\frac{dA_{tissue}}{dt} = PS \cdot (C_{u,vasc} - C_{u,tissue})$$

GI absorption (AbsorptionFluxSpec):

$$k_a = \frac{2.88 \cdot P_{eff} \cdot f_{ka}}{r}$$

where $P_{eff}$ is effective permeability (×10−4 cm/s), $f_{ka}$ is the segment-specific absorption fraction, and $r$ is particle radius (μm).

Tissue:plasma partition coefficients are computed via the Rodgers & Rowland method (Rodgers & Rowland, 2005, 2006), with the Berezhkovskiy correction for acids (Berezhkovskiy, 2004).

Prediction pipeline

The full pipeline combines mechanistic simulation with data-driven prediction:

  1. SMILES → molecular profile: RDKit descriptors, structural pKa classification, applicability domain assessment
  2. ADME prediction: Pre-trained XGBoost models for fu,p, CLint, RB:P, VDss (trained on TDC datasets; Huang et al., 2021), with DrugBank experimental fu,p enrichment where available
  3. IVIVE: CLint decomposition into per-enzyme affinities, Kp calculation
  4. PBPK simulation: 34-state ODE system solved via LSODA (Petzold, 1983)
  5. ML direct prediction: XGBoost Cmax model (trained on 1,128 drugs from multi-source clinical PK data)
  6. Meta-learner: Compound-type-adaptive geometric combination of PBPK and ML Cmax, calibrated via LOOCV on the holdout set (base compounds: engine 0.45 / ML 0.55; non-base compounds: engine 0.00 / ML 1.00)

Uncertainty propagation

All parameters are represented as Distribution(mean, cv, dist_type). Monte Carlo sampling draws N realizations from all parameter distributions simultaneously, solves the ODE for each, and aggregates the resulting PK endpoints into distributional summaries with prediction intervals. The graph topology is compiled once; only parameter values change across MC iterations ("compile once, parameterize many").

Multi-dose regimen simulation

Multi-dose pharmacokinetics are computed by an event-driven solver that wraps the single-dose ODE engine. Dose events are injected into the state vector between integration segments; the ODE right-hand side is not modified. This preserves the identity-blind engine invariant while supporting arbitrary dosing schedules (repeated oral, IV infusion, mixed regimens).

Steady-state detection applies a trough variation criterion (<5%) across the last three dosing intervals. The solver reports Css,max, Css,min, accumulation ratio (AR = Css,max / Cmax,first), and dose number at which steady state is reached.

Therapeutic drug monitoring

Given observed plasma concentrations from a patient, Sisyphus refines population-level parameter distributions into individual posteriors via importance sampling:

  1. Draw $N$ samples from prior parameter distributions (physiology and drug).
  2. For each sample, simulate the administered regimen and interpolate predicted concentration at each observation time.
  3. Compute per-sample likelihood assuming normally distributed assay error: $L_i = \prod_k \phi\left(C_{obs,k} \mid C_{pred,k}^{(i)},\ \sigma_{assay}\right)$
  4. Importance weights $w_i \propto L_i$, normalized so $\sum w_i = 1$.
  5. Effective sample size $ESS = 1 / \sum w_i^2$ monitors weight degeneracy.
  6. Weighted statistics yield posterior distributions for all PK parameters.

This mechanism bypasses the CLint prediction ceiling (R² ≈ 0.24): observed drug levels directly correct inaccurate population priors, reducing posterior CV by >50% in validation (see TDM validation).

Model-informed precision dosing

MIPD recommends adjusted doses to achieve a target steady-state concentration:

  1. Bayesian update at the observed dose yields a posterior Css distribution.
  2. Linear dose scaling: $dose_{new} = dose_{current} \times (C_{ss,target} / C_{ss,posterior})$
  3. Clamp to clinical dose range and round to a practical increment (default 25 mg).

Linear scaling assumes non-saturable metabolism, which holds for most drugs at therapeutic concentrations. For drugs with known nonlinear pharmacokinetics (e.g., phenytoin), this approximation should be used with caution.

Drug-drug interactions

DDI is modeled by adjusting enzyme abundances in the body graph prior to ODE compilation. The engine sees modified abundances and computes clearance as usual — no engine modifications are required.

Competitive inhibition:

$$E_{eff} = \frac{E_{base}}{1 + [I] / K_i}$$

Enzyme induction (Emax model):

$$E_{eff} = E_{base} \cdot \left(1 + \frac{E_{max} \cdot [I]}{EC_{50} + [I]}\right)$$

where $E_{base}$ is baseline enzyme abundance (pmol), $[I]$ is perpetrator plasma concentration, $K_i$ is the inhibition constant, and $E_{max}$/$EC_{50}$ are induction parameters. Preset perpetrators: ketoconazole, fluconazole, quinidine (CYP inhibitors) and rifampin (CYP3A4 inducer).

PK/PD link

Pharmacodynamic effects are computed from the concentration-time profile via an effect compartment with sigmoid Emax response:

Effect-site equilibration:

$$\frac{dC_e}{dt} = k_{e0} \cdot (C_p - C_e)$$

Sigmoid Emax response:

$$E = E_0 + \frac{E_{max} \cdot C_e^n}{EC_{50}^n + C_e^n}$$

where $k_{e0}$ is the effect-site equilibration rate constant (h−1), $E_0$ is the baseline effect, and $n$ is the Hill coefficient. This is implemented as analytical post-processing on the PK solution, not as additional ODE states, preserving engine isolation. Preset PD models are provided for midazolam (sedation) and warfarin (INR response).

Quickstart

Installation

pip install -e ".[dev,ml,chem]"

Pre-trained XGBoost models (fu,p, CLint, RB:P, VDss, Cmax) are required in models/adme/ and models/direct_pk/. Re-training scripts are provided in scripts/.

CLI

Six commands cover the clinical pharmacology workflow:

# Single-dose PK prediction
sisyphus predict --smiles "Cn1c(=O)c2c(ncn2C)n(C)c1=O" --dose 100

# Multi-dose regimen simulation (atorvastatin 40 mg QD × 14 days)
sisyphus simulate --smiles "CC(C)c1n(CC(O)CC(O)CC(=O)O)c(=O)..." \
    --dose 40 --interval 24 --doses 14

# TDM Bayesian update (midazolam 5 mg, observed 0.015 mg/L at t=1 h)
sisyphus tdm --smiles "c1ccc2c(c1)C(=NC(=O)N2)c1ccccc1F" \
    --dose 5 --obs "1.0:0.015"

# DDI prediction (midazolam + ketoconazole inhibition)
sisyphus ddi --smiles "c1ccc2c(c1)C(=NC(=O)N2)c1ccccc1F" \
    --dose 5 --inhibitor ketoconazole

# MIPD dose recommendation (target Css,max = 0.02 mg/L)
sisyphus dose-adjust --smiles "c1ccc2c(c1)C(=NC(=O)N2)c1ccccc1F" \
    --dose 5 --obs "1.0:0.015" --target-css 0.02

# Holdout benchmark
sisyphus benchmark --holdout

All commands accept --verbose for debug-level logging.

Python API

from sisyphus.pipeline.predict import predict

result = predict("Cn1c(=O)c2c(ncn2C)n(C)c1=O", dose_mg=100.0)

print(result.pk.cmax.mean)    # 1.52 mg/L
print(result.method)          # "hybrid"
print(result.confidence)      # "high"

Engine-only mode (known compound parameters)

For validation or mechanistic studies, the engine can be driven directly from compound YAML files, bypassing ADME prediction:

from pathlib import Path
import numpy as np
from sisyphus.graph.builder import build_from_yaml
from sisyphus.compounds import load_compound
from sisyphus.engine.compiler import ODECompiler, ResolvedParams
from sisyphus.engine.solver import solve
from sisyphus.pk.endpoints import compute_endpoints
import sisyphus.engine.flux  # register flux functions

graph = build_from_yaml(Path("data/physiology/reference_man.yaml"))
drug = load_compound(Path("data/compounds/midazolam.yaml"))

compiled = ODECompiler().compile(graph)
rng = np.random.default_rng(42)
params = ResolvedParams(graph.sample(rng), drug.sample(rng))

y0 = np.zeros(compiled.n_states)
y0[compiled.state_index[drug.administration_node]] = drug.dose_mg

result = solve(compiled, params, y0, t_span=(0, 24))
pk = compute_endpoints(result)

print(f"Cmax: {pk.cmax.mean:.4f} mg/L")  # 0.0069 mg/L (matches Omega ±0.5%)

Monte Carlo uncertainty

from sisyphus.engine.uncertainty import UncertaintyEngine

ue = UncertaintyEngine()
mc = ue.propagate_fast(compiled, graph, drug, n_samples=1000)

print(mc.pk.cmax)                # Distribution(mean=1.76, cv=0.19)
print(mc.cmax_90ci)              # (1.28, 2.35) mg/L
print(len(mc.cmax_samples))      # 1000 individual realizations

Validation

Engine validation against Omega PBPK

Four drugs with known compound parameters were simulated and compared against the Omega PBPK ODE engine (35-state hardcoded model):

Drug Dose Sisyphus Cmax (mg/L) Omega Cmax (mg/L) Relative error
Midazolam 2 mg PO 0.006911 0.006943 0.5%
Caffeine 100 mg PO 1.7151 1.7139 0.1%
Warfarin 10 mg PO 0.4917 0.4922 0.1%
Propranolol 80 mg PO 0.1353 0.1355 0.1%

Mass balance error < 10−12 for all simulations.

Holdout benchmark (SMILES → Cmax)

External validation on a Murcko scaffold-stratified holdout set (seed=42, never used in training or model selection). The holdout set was expanded from 61 to 107 drugs by integrating observed concentration–time profiles from the Open Systems Pharmacology (OSP) repository, curated literature PK data, and FDA DailyMed labels. Performance is reported using AAFE (Absolute Average Fold Error; Obach et al., 1997):

$$AAFE = 10^{\operatorname{mean}\left(\left|\log_{10}\frac{C_{max,pred}}{C_{max,obs}}\right|\right)}$$

Metric Value N
Holdout AAFE (meta-learner) 2.283 107
Holdout %2-fold 54.2% 107
In-domain AAFE 2.100 83
Engine-only AAFE 3.415 107
ML-only AAFE 2.336 107

The meta-learner adaptively combines mechanistic PBPK simulation with data-driven XGBoost Cmax prediction via LOOCV-calibrated geometric weighting. Weights are compound-type dependent: basic compounds receive a 0.45/0.55 engine/ML split (the PBPK engine adds value for bases), while non-base compounds rely entirely on the ML track (weight stability 82% across LOO folds). In-domain AAFE (N=83) excludes 24 drugs flagged as out-of-applicability-domain (prodrugs, high-MW, extreme lipophilicity) or known extended-release formulation mismatches.

Multi-dose regimen validation

Three drugs were simulated at clinical dosing regimens and compared against FDA-label steady-state Cmax values:

Drug Regimen Predicted Css,max (mg/L) FDA label Css,max (mg/L) Fold error
Atorvastatin 40 mg QD 0.027 0.029 0.93
Metformin 500 mg BID 0.55 1.0 0.55
Warfarin 5 mg QD 0.34 1.4 0.24

Atorvastatin (CYP3A4-mediated, moderate protein binding) was predicted within 7% of the label value. Metformin (renal elimination-dominant, fu ≈ 1.0) and warfarin (fu = 0.01, highly protein-bound) show expected under-prediction consistent with the model’s known limitations in renal clearance modeling and CLint over-prediction for highly bound compounds. Accumulation ratio direction was correct for all three drugs. Steady-state detection operated correctly in all cases.

TDM validation

Bayesian update was validated in two stages: a single-drug functional test, then a multi-drug benchmark across diverse pharmacokinetic profiles.

Single-drug validation (midazolam, 5 mg PO, one observation at t = 1 h, 10% assay CV):

Metric Prior Posterior
Cmax CV 44.3% 19.8%
ESS 586.6 (29.3% of 2,000)
CV reduction 55.4%

Multi-drug benchmark (5 holdout drugs, synthetic patient observations scaled from engine C(t) profiles to observed Cmax, 10% log-normal assay noise, seed = 42):

Drug Type 1-obs CV reduction 2-obs CV reduction 3-obs CV reduction 1-obs ESS
Morphine base 76.3% 77.0% 74.6% 428
Amantadine base 74.0% 74.5% 74.7% 514
Ketorolac acid 87.7% 92.6% 90.1% 2.8
Clozapine neutral 68.7% 76.2% 76.9% 482
Rivaroxaban neutral 83.8% 93.3% 98.3% 7.1

Across all 15 runs (5 drugs × 3 observation scenarios): mean CV reduction 81.2%, mean error reduction 79.8%, 90% CI coverage 67%. A single observation suffices to reduce Cmax CV by 70–88% for drugs where the population prior fold error is below 2.5×. For drugs with larger prior errors (ketorolac, fold error 3.25×) or multi-observation scenarios, effective sample size degrades below 10, indicating particle degeneracy in the importance sampler. Sequential Bayesian methods (ensemble Kalman filter, particle filter) would be required for these cases.

Timepoint sensitivity analysis (morphine, single observation): t = 1.0 h (near Tmax) yielded maximal CV reduction (76.3%); observations beyond 4 h post-dose provided diminishing information (CV reduction 34%). Seed sensitivity across three random seeds was 0.8%, confirming robustness at N = 2,000 prior samples.

Performance

Operation Time Configuration
Full prediction (SMILES → Cmax) 414 ms Deterministic, single core
ODE solve (full fidelity) 106 ms LSODA, rtol=10−8, atol=10−10
ODE solve (MC fast path) 33 ms LSODA, rtol=10−4, atol=10−6
MC N=1,000 33.5 s Pure Python RHS (no JIT compilation)
RHS evaluation 31 μs 54 flux specs per call

Single-patient deterministic prediction completes in <500 ms, compatible with interactive clinical decision support workflows. MC propagation at N=1,000 requires ~34 s due to pure Python ODE evaluation; JIT compilation (e.g., via Numba) is an optimization path not yet pursued.

Test suite

357 unit and integration tests covering graph construction, ODE compilation, flux functions, solver correctness, mass balance, ADME prediction, meta-learner calibration, multi-dose regimen, TDM Bayesian update, MIPD dose recommendation, DDI, PK/PD, and holdout benchmark reproducibility.

Architecture

SMILES + dose
    │
    ▼
 predict ──► DrugOnGraph (enzyme-level, all values are Distribution)
                  │
                  ▼
             engine ◄── BodyGraph (from YAML)
             (compile graph → ODE → solve → MC propagate)
                  │
                  ▼
               pk (Cmax, AUC, t½ from SimResult)
                  │
    ml ───────────┤
    (direct PK)   │
                  ▼
             pipeline (meta-learner → final PredictionResult)
                  │
       ┌──────────┼──────────┐
       ▼          ▼          ▼
    regimen      ddi       pkpd
   (multi-dose, (enzyme    (effect
    TDM, MIPD)  adj.)     compartment)
Layer Responsibility Depends on
graph/ BodyGraph, node/edge types, YAML builder core
engine/ ODE compiler, flux registry, solver, MC core, graph
predict/ SMILES → chemistry → ADME → DrugOnGraph core
ml/ XGBoost Cmax, meta-learner core
pk/ SimResult → PKEndpoints core
regimen/ Multi-dose solver, TDM Bayesian update, MIPD core, engine, graph
pipeline/ Orchestrator wiring all layers all layers
ddi.py Drug-drug interactions (competitive inhibition, Emax induction) core, graph
pkpd.py PK/PD effect modeling (effect compartment, sigmoid Emax) core

Layer isolation. No cross-layer imports outside designated dependencies. predict does not import engine. engine does not import predict. regimen wraps engine without modifying it. Shared data types live in core.py.

Design principles

  1. Identity-blind engine. The ODE compiler and flux functions operate on node/edge types, never on identities. No string matching on organ names, enzyme names, or drug names exists in engine/. Replacing all organ names with random strings produces identical numerical results.

  2. Distribution-native. All physiological and drug parameters are Distribution objects. Point estimates are represented as Distribution(mean=x, cv=0). The uncertainty system is not an add-on; it is the system’s native representation.

  3. Compile once, parameterize many. Graph topology is compiled into an ODE skeleton once. MC iterations change only parameter values, not structure. 1,000 MC samples = 1 compilation + 1,000 ODE solves.

Extending the Model

The architecture is designed so that new compartments, routes, populations, interaction models, and clinical workflows require zero changes to the ODE engine. This was validated empirically: subcutaneous injection, pediatric physiology, tumor compartment, DDI, PK/PD, multi-dose regimen, and TDM were each implemented with 0 lines changed in src/sisyphus/engine/.

New organ (tumor compartment)

nodes:
  - name: tumor
    type: organ
    volume: 0.05
    composition: {fn: 0.013, fp: 0.010, fw: 0.700, pH: 6.8}
edges:
  - {source: arterial_blood, target: tumor, type: flow, flow_fraction: 0.005}
  - {source: tumor, target: venous_blood, type: flow}

New route (subcutaneous injection)

graph.add_node(Node(name="sc_depot", node_type="lumen", volume=Distribution(0.01)))
graph.add_edge(AbsorptionEdge(source="sc_depot", target="venous_blood",
                               ka_fraction=Distribution(1.0)))

New population (pediatric)

Allometrically scaled physiology (cardiac output ∝ BW0.75) with ontogeny-adjusted enzyme abundances (e.g., CYP3A4 at 50% of adult at age 5). Same graph structure, different YAML parameters.

Drug-drug interactions

Competitive CYP inhibition via pre-simulation enzyme abundance adjustment:

from sisyphus.ddi import apply_inhibition, KETOCONAZOLE

inhibited_graph = apply_inhibition(graph, KETOCONAZOLE)
# Midazolam AUC increases 12x (clinical reference: ~15x)

PK/PD modeling

Effect compartment with sigmoid Emax response, computed as post-processing on the concentration-time profile:

from sisyphus.pkpd import compute_effect, PDModel

pd = PDModel(ke0=0.5, emax=100.0, ec50=0.05, hill=2.0)
effect = compute_effect(sim_result, pd)

Limitations

  • Small-molecule oral PK only. Biologics (antibodies, ADCs), parenteral formulations beyond SC, and non-oral routes (inhalation, topical) are not validated.
  • No prodrug metabolism. Cmax is predicted for the parent compound. Prodrugs (e.g., valacyclovir, fesoterodine) are flagged as out-of-applicability-domain.
  • Simplified pKa. Ionization state is classified by structural rules (carboxylic acid → 4.5, aliphatic amine → 9.0), not computed quantum-mechanically. This limits Kp accuracy for highly ionized compounds.
  • No Phase II metabolism. Glucuronidation (UGT), sulfation (SULT), and acetylation (NAT2) are not modeled. Drugs primarily cleared by conjugation will be under-predicted.
  • No transporter-mediated disposition in ODE. P-gp efflux is handled via a binary permeability correction, not as a mechanistic transport term in the ODE.
  • CLint prediction is the weakest link. The XGBoost CLint model achieves R² ≈ 0.24 on TDC Hepatocyte_AZ (scaffold-split CV). This ceiling persists across molecular representations (Morgan FP, MACCS keys, atom-pair FP, MoLFormer, ChemBERTa, Uni-Mol, Chemprop D-MPNN), model architectures (XGBoost, Random Forest, Ridge, GNN), data scales (978–1,910 compounds), and alternative formulations (classification, BDE reactivity features, direct CL/F bypass, AUC decomposition). Twenty-seven controlled experiments evaluating more than 60 distinct approaches were conducted; none produced a meaningful reduction in holdout AAFE. The primary bottleneck is assay noise in public hepatocyte clearance data, not model capacity or molecular representation. Bayesian TDM partially mitigates this at the individual patient level: observed drug concentrations correct inaccurate population priors, reducing posterior CV by >50% (see TDM validation).
  • Error cancellation constrains component-level improvements. The IVIVE pipeline (fu,p × CLint × scaling → CLh) exhibits systematic error cancellation: improving any single ADME component (e.g., CLint R² from 0.21 to 0.33 via data expansion) worsens overall AAFE because the error balance with other components is disrupted. Simultaneous replacement of all ADME models also failed to improve AAFE (+0.023), and post-hoc meta-learner optimization across more than 60 blending strategies (stacking, analog correction, rank aggregation, Bayesian model averaging, ensemble selection, isotonic/LOWESS calibration, substructure correction, disagreement routing, and others) confirmed that all such combinations produce holdout errors correlated at r > 0.95 with the baseline meta-learner. The current compound-type-adaptive geometric blend is provably near-optimal at this sample size. Measured ADME inputs (experimental fu,p and CLint) reduce engine AAFE from 2.33 to 1.98, confirming that the mechanistic architecture is sound when inputs are accurate.
  • RB:P defaults to 1.0. The RBP model (R² = −0.08 on external data) is effectively disabled; all drugs are assumed to have equal blood and plasma concentrations.
  • MIPD assumes linear pharmacokinetics. Dose recommendations use linear scaling, which may be inaccurate for drugs with saturable metabolism (e.g., phenytoin) or nonlinear protein binding.
  • TDM importance sampling degenerates for large prior errors. When the population prior is far from the individual truth (fold error >3×) or multiple observations are used (≥3), the effective sample size drops below 10, indicating particle weight degeneracy. Sequential Bayesian methods (EnKF, particle filter) would address this.

Project Structure

src/sisyphus/
├── core.py              # Distribution, TissueComposition, data contracts
├── descriptors.py       # Morgan fingerprints + RDKit descriptors
├── compounds.py         # Compound YAML → DrugOnGraph loader
├── ddi.py               # Drug-drug interaction modeling
├── pkpd.py              # PK/PD effect compartment + Emax
├── cli.py               # Command-line interface (6 commands)
│
├── graph/               # Body graph definition and construction
│   ├── types.py         # Node, Edge type hierarchy (frozen dataclasses)
│   ├── body.py          # BodyGraph (add/remove/validate/sample)
│   ├── builder.py       # YAML → BodyGraph with flow conservation check
│   └── presets.py       # reference_man(), reference_woman()
│
├── engine/              # ODE compilation and solving (identity-blind)
│   ├── compiler.py      # ODECompiler, CompiledODE, ResolvedParams
│   ├── flux.py          # FluxSpec implementations (6 transport types)
│   ├── solver.py        # LSODA wrapper (solve, solve_mc)
│   └── uncertainty.py   # Monte Carlo propagation
│
├── predict/             # SMILES → drug parameterization
│   ├── chemistry.py     # Molecular profiling, pKa, AD assessment
│   ├── adme.py          # XGBoost ADME property prediction
│   └── ivive.py         # In vitro → in vivo extrapolation, Kp
│
├── ml/                  # Data-driven PK prediction
│   ├── features.py      # Feature vector construction
│   ├── models.py        # XGBoost Cmax predictor
│   └── ensemble.py      # Meta-learner (PBPK + ML combination)
│
├── pk/                  # PK endpoint extraction
│   ├── endpoints.py     # SimResult → PKEndpoints
│   ├── nca.py           # Non-compartmental analysis (AUC, t½)
│   └── analytical.py    # Closed-form 1-cpt and 2-cpt solutions
│
├── regimen/             # Multi-dose and clinical pharmacology
│   ├── types.py         # DosingEvent, DosingRegimen (frozen dataclasses)
│   ├── solver.py        # Event-driven multi-dose solver
│   ├── profile.py       # Steady-state detection, Css metrics
│   ├── tdm.py           # Bayesian TDM via importance sampling
│   └── dosing.py        # MIPD dose recommendation
│
├── validation/          # Benchmarking infrastructure
│   ├── reference.py     # Clinical PK reference loader (331 drugs)
│   ├── benchmark.py     # Holdout benchmark runner
│   ├── metrics.py       # AAFE, fold error, PI coverage
│   └── split.py         # Scaffold-stratified splitting
│
└── pipeline/            # End-to-end orchestration
    ├── predict.py       # SMILES → PredictionResult
    └── config.py        # Pipeline configuration

data/
├── physiology/          # BodyGraph YAML definitions
├── compounds/           # Curated compound configurations
└── reference/           # Clinical PK reference data, holdout split

models/                  # Pre-trained XGBoost models (not in git)

Predecessor

Sisyphus inherits validated data assets from Omega PBPK (591 commits) but not its architecture:

Inherited (data) Not inherited (architecture)
331-drug clinical reference 35-state hardcoded ODE system
Scaffold-stratified holdout split Organ-specific CLint fields
ICRP physiology values Sequential ADME → IVIVE chain
Pre-trained XGBoost models Point-estimate pipeline
Rodgers & Rowland tissue compositions Post-hoc hybrid selector

Key empirical findings from Omega that informed Sisyphus:

  • Data quality dominates model choice. 14 reference corrections reduced AAFE by 47.5% with zero model changes.
  • Gut CLint > hepatic CLint for Cmax. Global sensitivity analysis (Sobol): gut ST=0.47, hepatic ST=0.00.
  • Meta-learner > fixed ensemble. Feature importance: ML Cmax 50%, PBPK Cmax 26%.

References

  • Berezhkovskiy, L. M. (2004). Volume of distribution at steady state for a linear pharmacokinetic system with peripheral elimination. J Pharm Sci, 93(6), 1628–1640.
  • Houston, J. B. (1994). Utility of in vitro drug metabolism data in predicting in vivo metabolic clearance. Biochem Pharmacol, 47(9), 1469–1479.
  • Huang, K., et al. (2021). Therapeutics Data Commons: Machine learning datasets and tasks for drug discovery and development. NeurIPS Datasets and Benchmarks.
  • ICRP (2002). Basic anatomical and physiological data for use in radiological protection: reference values. ICRP Publication 89.
  • Obach, R. S., et al. (1997). The prediction of human pharmacokinetic parameters from preclinical and in vitro metabolism data. J Pharmacol Exp Ther, 283(1), 46–58.
  • Petzold, L. R. (1983). Automatic selection of methods for solving stiff and nonstiff systems of ordinary differential equations. SIAM J Sci Stat Comput, 4(1), 136–148.
  • Poulin, P., & Theil, F. P. (2002). Prediction of pharmacokinetics prior to in vivo studies. J Pharm Sci, 91(4), 940–951.
  • Rodgers, T., & Rowland, M. (2005). Physiologically based pharmacokinetic modelling 2: Predicting the tissue distribution of acids, very weak bases, neutrals and zwitterions. J Pharm Sci, 95(6), 1238–1257.
  • Rodgers, T., & Rowland, M. (2006). Mechanistic approaches to volume of distribution predictions: Understanding the processes. Pharm Res, 24(5), 918–933.
  • Shimada, T., et al. (1994). Interindividual variations in human liver cytochrome P-450 enzymes involved in the oxidation of drugs, carcinogens and toxic chemicals. J Pharmacol Exp Ther, 270(1), 414–423.
  • Yang, J., Jamei, M., Yeo, K. R., Tucker, G. T., & Rostami-Hodjegan, A. (2007). Prediction of intestinal first-pass drug metabolism. Curr Drug Metab, 8(7), 676–684.
  • Yu, L. X., & Amidon, G. L. (1999). A compartmental absorption and transit model for estimating oral drug absorption. Int J Pharm, 186(2), 119–125.

How to Cite

If you use Sisyphus in your research, please cite:

Yoon, J. M. (2026). Sisyphus (v1.0.0): Graph-based whole-body PBPK
simulation with native uncertainty propagation.
https://github.com/jam-sudo/Sisyphus

Requirements

  • Python ≥ 3.10
  • numpy, scipy, pyyaml (core)
  • rdkit, xgboost, scikit-learn (prediction)

License

MIT

About

Digital Twin

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages