Skip to content

LAPKB/pharmsol

Repository files navigation

pharmsol

Build Documentation crates.io

A high-performance Rust library for pharmacokinetic/pharmacodynamic (PK/PD) simulation using analytical solutions, ordinary differential equations (ODEs), or stochastic differential equations (SDEs).

Installation

Add pharmsol to Cargo.toml:

cargo add pharmsol

Quick Start

Most Rust-first workflows start with one of the equation macros: analytical!, ode!, or sde!. Here is a one-compartment oral model using analytical! with a derived analytical structure input:

use pharmsol::{Parameters, prelude::*};

let analytical = analytical! {
    name: "one_cmt_oral",
    params: [ka, ke0, v],
    derived: [ke],
    covariates: [wt],
    states: [gut, central],
    outputs: [cp],
    routes: [
        bolus(oral) -> gut,
    ],
    structure: one_compartment_with_absorption,
    derive: |_t| {
        ke = ke0 * (wt / 70.0).powf(0.75);
    },
    out: |x, _t, y| {
        y[cp] = x[central] / v;
    },
};

let subject = Subject::builder("patient_001")
    .bolus(0.0, 500.0, "oral")
    .missing_observation(0.5, "cp")
    .missing_observation(1.0, "cp")
    .missing_observation(2.0, "cp")
    .missing_observation(4.0, "cp")
    .covariate("wt", 0.0, 75.0)
    .build();

let parameters = Parameters::with_model(
    &analytical,
    [("ka", 1.2), ("ke0", 0.08), ("v", 194.0)],
)
.unwrap();

let predictions = analytical
    .estimate_predictions(&subject, &parameters)
    .unwrap();

Modeling Surfaces

Here is the same one-compartment IV setup written as an ODE:

use pharmsol::prelude::*;

let ode = ode! {
    name: "one_cmt_iv",
    params: [ke, v],
    states: [central],
    outputs: [cp],
    routes: [
        infusion(iv) -> central,
    ],
    diffeq: |x, _p, _t, dx, _cov| {
        dx[central] = -ke * x[central];
    },
    out: |x, _p, _t, _cov, y| {
        y[cp] = x[central] / v;
    },
};

See examples/analytical_readme.rs, examples/ode_readme.rs, examples/sde_readme.rs, examples/dsl_jit_analytical_covariates.rs, examples/analytical_vs_ode.rs, and examples/compare_solvers.rs. For migration-oriented notes, see docs/analytical-authoring-migration.md and docs/ode-authoring-migration.md.

Built-In Analytical Kernels

  • One-compartment with IV infusion
  • One-compartment with IV infusion and oral absorption
  • Two-compartment with IV infusion
  • Two-compartment with IV infusion and oral absorption
  • Three-compartment with IV infusion
  • Three-compartment with IV infusion and oral absorption

DSL and Runtime Targets

If the model needs to be loaded or compiled at runtime, pharmsol also provides a DSL with the same broad modeling coverage: ODE, analytical, and SDE authoring. The DSL can target an in-process JIT runtime, native ahead-of-time artifacts, or WASM bundles depending on how you want to ship and execute the model.

  • dsl-jit: compile DSL source into a runtime model inside the current process.
  • dsl-aot and dsl-aot-load: emit a native artifact and load it later.
  • dsl-wasm: compile and execute portable WASM model artifacts.

See examples/dsl_runtime_jit.rs for the in-repo JIT flow and examples/dsl_jit_analytical_covariates.rs for a small analytical covariate example written both as DSL JIT source and as an analytical! model. The companion pharmsol-examples crate includes end-to-end native AOT and WASM runtime examples.

Performance

Analytical solutions provide 20-33× speedups compared to equivalent ODE formulations. See benchmarks for details.

Non-Compartmental Analysis (NCA)

pharmsol includes a complete NCA module for calculating standard pharmacokinetic parameters.

use pharmsol::prelude::*;
use pharmsol::nca::NCAOptions;

let subject = Subject::builder("patient_001")
    .bolus(0.0, 100.0, "oral")  // 100 mg oral dose
    .observation(0.5, 5.0, "cp")
    .observation(1.0, 10.0, "cp")
    .observation(2.0, 8.0, "cp")
    .observation(4.0, 4.0, "cp")
    .observation(8.0, 2.0, "cp")
    .build();

let result = subject.nca(&NCAOptions::default()).expect("NCA failed");

println!("Cmax: {:.2}", result.exposure.cmax);
println!("Tmax: {:.2} h", result.exposure.tmax);
println!("AUClast: {:.2}", result.exposure.auc_last);

if let Some(ref term) = result.terminal {
    println!("Half-life: {:.2} h", term.half_life);
}

Supported NCA Parameters:

  • Exposure: Cmax, Tmax, Clast, Tlast, AUClast, AUCinf, tlag
  • Terminal: λz, t½, MRT
  • Clearance: CL/F, Vz/F, Vss
  • IV-specific: C0 (back-extrapolation), Vd
  • Steady-state: AUCtau, Cmin, Cavg, fluctuation, swing

Links

About

Rust library for solving analytic and ODE-defined pharmacometric models.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages