Skip to contents

Introduction

rxode2 and Simulx are both tools for pharmacometric simulation, but they differ substantially in design philosophy, licensing, and ecosystem integration.

  • rxode2 is an open-source R package. Models are defined in R using rxode2’s own mini-language, compiled to a shared library, and solved within the R session. It is fully scriptable and integrates with nlmixr2 for parameter estimation.

  • Simulx is a commercial clinical trial simulation application (part of the MonolixSuite, distributed by Simulations Plus / Lixoft). It provides a graphical user interface (GUI) as its primary interaction mode, and an R scripting interface via the lixoftConnectors package. Models are specified in mlxtran – the same language used by Monolix for estimation – so Monolix projects can be imported directly with no re-implementation. A commercial or academic license is required.

Shared capabilities

  • ODE-based pharmacometric models
  • Between-subject variability (BSV / omega)
  • Residual error models
  • Covariate distributions (continuous and categorical)
  • Population simulation across many subjects
  • Multiple dosing regimen groups
  • Parameter uncertainty simulation
  • VPC (visual predictive check) workflows
  • Clinical trial scenario design and simulation

Features rxode2 has that Simulx does not

No license required

rxode2 is entirely open-source (GPL >= 3). Simulx requires a commercial license from Simulations Plus; an academic license is available free of charge but must be requested and renewed. rxode2 runs without any registration or license file on any machine with R and a C compiler.

Fully scriptable, reproducible workflows

rxode2 is a pure R package. Every aspect of model definition, simulation, and output processing is expressed in R code, making workflows fully reproducible and straightforward to version-control, review, and automate in CI/CD pipelines.

Simulx’s primary interface is a GUI application. Its R scripting layer (lixoftConnectors) is a thin connector to the underlying Simulx engine rather than a native R simulation library, so GUI state and R scripts are partially coupled.

library(rxode2)

# Entirely self-contained R script -- no GUI, no license file
mod <- rxode2({
  KA <- exp(tka + eta.ka)
  CL <- exp(tcl + eta.cl)
  d/dt(depot) <- -KA * depot
  d/dt(centr) <- KA * depot - CL / V * centr
  cp          <- centr / V
})

et  <- et(amt = 100, time = 0) |> et(seq(0, 24, by = 1))
sim <- rxSolve(mod, et,
               params = c(tka = log(0.5), tcl = log(4), V = 10),
               omega  = lotri(eta.ka ~ 0.09, eta.cl ~ 0.09),
               nSub   = 100)

Parameter estimation via nlmixr2

rxode2 models can be passed directly to nlmixr2 for population parameter estimation (FOCE, FOCEi, SAEM, etc.) using the exact same model object used for simulation. Simulx is simulation-only; estimation is performed in Monolix separately.

OpenMP parallelism across subjects

rxode2’s LSODA solver is implemented in thread-safe C, enabling genuine parallel ODE solving across subjects via OpenMP within a single R process. Simulx uses a C++ solver internally and parallelises across CPU cores through its own engine, but this is not directly controlled from R.

Model piping for incremental modification

rxode2 model objects support the native R pipe (|>) to clone and modify a model incrementally without rewriting the full specification.

base <- rxode2({
  d/dt(depot) <- -KA * depot
  d/dt(centr) <- KA * depot - CL / V * centr
  cp          <- centr / V
})

# Add population structure and residual error
full <- base |>
  model({
    KA <- exp(tka + eta.ka)
    CL <- exp(tcl + eta.cl)
  }, append = FALSE) |>
  ini({
    tka <- log(0.5); eta.ka ~ 0.09
    tcl <- log(4);   eta.cl ~ 0.09
    V   <- 10
    add.sd <- 0.5
  }) |>
  model(cp ~ add(add.sd), append = TRUE)

# Sensitivity run: fix BSV on KA
sens <- full |> ini(fix(eta.ka))

Simulx does not have an equivalent R-level model algebra; scenario modifications are made through the GUI or via lixoftConnectors function calls that manipulate named elements of a loaded project.

Symbolic Jacobians and forward sensitivities

rxode2 automatically derives the symbolic Jacobian and forward- sensitivity equations, used by nlmixr2’s FOCEi algorithm for exact gradient-based parameter estimation. These extend to third-order sensitivities and to jump (event) sensitivities – exact derivatives with respect to dosing parameters such as bioavailability, lag time, infusion rate, duration, and amount.

1-3 compartment analytical solutions with exact gradients

linCmt() provides analytical solutions for one-, two-, and three-compartment PK models with gradients via Stan math auto-differentiation. Simulx’s mlxtran language has its own closed-form solution for linear compartmental models with no transit compartments (the pkmodel macro), falling back to ODE integration otherwise, but it does not expose auto-differentiated gradients through this path. rxode2 can also detect a 1-3 compartment linear PK ODE system and transparently solve it through this analytical path (rxSolve(..., useLinCmt = TRUE), the default), falling back to the ODE solver if the converted model cannot be compiled.

Multiple ODE solver backends

rxode2 offers several solver backends selectable per run: thread-safe C LSODA (default), Fortran LSODA, DOP853 (explicit 8th-order Runge-Kutta for non-stiff systems), a stiff Rosenbrock method (ros4), and AutoSwitch composite methods (for example method = "dop853+ros4") that probe each segment with a non-stiff primary and reactively fall back to a stiff secondary only where stiffness is detected. Simulx uses a single C++ LSODA-based solver.

Delay differential equations

rxode2 solves delay differential equations through delay(state, T), which evaluates an ODE state at the past time t - T using dense-output interpolation, with forward sensitivities generated automatically so the models stay estimable in nlmixr2.

Out-of-memory simulation and distributed parallelism

For very large trial simulations, passing a file prefix to rxSolve() splits subjects into RAM-sized chunks (auto-sized with rxMemoryEstimate()), solves each, and writes them to Parquet (or .rds) behind a lightweight object that supports lazy dplyr/DuckDB queries, so an out-of-memory result is never fully materialized. Chunks can be dispatched to mirai daemons (rxSolve(..., parallel = n)) for distributed/HPC execution, all controlled directly from R.

rxSolve(mod, params, ev, file = tempfile("rx"), parallel = 4)

Runs anywhere without infrastructure

rxode2 runs on any machine with R – laptops, CI servers, Docker containers, or Shiny apps. Simulx requires the MonolixSuite installation and a valid license to be present on the machine.

Features Simulx has that rxode2 does not

GUI for interactive exploration

Simulx’s primary strength is its point-and-click GUI. The Exploration workflow lets modelers interactively sweep parameter values and dosing regimens for a typical individual with real-time graphical output – no code required. This low-friction interface is valuable for non-programmers and for rapid “what-if” exploration before committing to a full simulation script.

rxode2 is code-only; interactive exploration requires writing R code or building a custom Shiny interface.

Direct Monolix project import

Because Simulx uses the same mlxtran model language as Monolix, a Monolix estimation project can be imported into Simulx in one click: the model equations, parameter estimates, omega and sigma matrices, and covariate distributions are all carried over automatically with zero re-implementation.

rxode2 uses a different model language. Monolix models can be converted via the monolix2rx package, which translates mlxtran to rxode2 syntax and runs an automatic validation comparing PRED/IPRED between the two tools. Models that pass validation can be simulated in rxode2 with confidence; models that do not pass require manual review.

Built-in scenario management and result display

Simulx provides a structured GUI workflow for defining named simulation scenarios (groups with different doses, covariates, or parameter values), running them, and visualizing results in interactive tables and plots – all within the application.

In rxode2 all scenario management, tabulation, and plotting is done in R using general-purpose packages (e.g., ggplot2, data.table), which gives more flexibility but requires more code.

Standardized clinical trial simulation workflow

Simulx’s GUI enforces a clear three-step workflow – Definition (parameters, treatments, outputs, covariates), Exploration (typical individual), and Simulation (population) – that guides users toward a complete and well-structured simulation. This structured approach reduces the risk of ad hoc or incomplete simulation setups.

rxode2 imposes no workflow structure; the user is responsible for organizing their simulation code.

Monolix-to-rxode2 import via monolix2rx

For users who estimate in Monolix and want to simulate in rxode2, the monolix2rx package (part of the nlmixr2 ecosystem) converts a Monolix project to an rxode2 model and automatically validates the conversion by comparing PRED/IPRED against the original Monolix output. A passing validation gives confidence that the rxode2 model is numerically equivalent to the Monolix model.

library(monolix2rx)

# Convert a Monolix project and validate automatically
mod <- monolix2rx("path/to/run001.mlxtran")

# Simulate the converted model in rxode2
rxSolve(mod, event_table, nSub = 1000)

This bridges the Monolix/Simulx and rxode2/nlmixr2 ecosystems, allowing estimation in Monolix and fast scripted simulation in rxode2.

Summary table

Feature rxode2 Simulx
License open-source (GPL >= 3) commercial (free academic)
Primary interface R code GUI + lixoftConnectors R API
Model language rxode2 mini-language mlxtran
Monolix project import monolix2rx (with auto-validation) direct (same language)
Re-implementation risk mitigated: monolix2rx auto-validates PRED/IPRED none
Simulation engine rxode2 C/Fortran solver Simulx C++ solver
ODE solver options LSODA (C/Fortran), DOP853, ros4, "dop853+ros4" single C++ LSODA-based
1-3 cmt analytical solution linCmt() with gradients pkmodel macro (linear, no transit cmts); no exposed gradients
Automatic ODE -> linCmt() conversion yes (useLinCmt=TRUE) no
Delay differential equations (delay()) yes no
Symbolic Jacobians / sensitivities yes (up to 3rd order + jump sensitivities) no
Parameter estimation via nlmixr2 no (Monolix only)
OpenMP parallelism (R-controlled) yes engine-internal
Distributed / cluster parallelism yes (mirai) engine-internal
Out-of-memory / disk-backed solve yes (rxSolve(file=), Parquet/DuckDB) no
Model piping (\|>) yes no
GUI / interactive exploration no (code only) yes
Built-in scenario management no (use R code) yes
Built-in result visualisation no (use ggplot2 etc.) yes
Monolix ecosystem integration via monolix2rx native
nlmixr2 ecosystem integration native no
Runs without installed application yes no
CRAN yes RsSimulx connector only; needs licensed Simulx app + non-CRAN lixoftConnectors