C++ code generation for ODEs with sensitivity propagation.
cppDE writes, compiles and runs a C++ solver for a system of ordinary differential equations, or C++ code for algebraic functions, given as equations in R. Derivatives with respect to the parameters are propagated forward on dual numbers or backward by a discrete adjoint, to first and second order.
- Solvers: variable-order BDF/NDF and Adams multistep in Nordsieck form, adapted from SUNDIALS/CVODE; Rosenbrock4 extended from Boost.Odeint; the Tsitouras 5(4) pair, an explicit Runge-Kutta method with dense output
- Sensitivities in both directions: forward mode carries one tangent per parameter through the solve; reverse mode returns the gradient of a functional in one backward sweep, at a cost independent of the parameter count
- Second order: exact Hessians, forward over forward or forward over reverse
- Events: time-based and root-triggered, with the saltation correction of first- and second-order sensitivities across a jump
- Code generation on an expression graph: Jacobians and derivative contractions by automatic differentiation, emitted as straight-line C++, with automatic sparsity detection and KLU factorisation for large systems
cvode(): the same models on SUNDIALS CVODES, with its forward sensitivities and adjointcppFUN(): the same code generation for algebraic functions, with Jacobian, Hessian and vector-Jacobian products- Batched solving:
solveODEBatch()integrates many conditions in one.Callover OpenMP threads, without the fork and serialisation ofparallel::mclapply()
# install.packages("devtools")
devtools::install_github("dModverse/cppDE")Model code is generated and compiled at run time, so a C++17 compiler and Python with SymPy are required. Windows users need Rtools.
The package installs and runs without any system library. Three features
are gated on one, detected by ./configure at install time:
| Feature | Needs | Without it |
|---|---|---|
cvode() backend |
SUNDIALS (>= 6.0) | the native solvers are unaffected |
| sparse Jacobian path | SuiteSparse / KLU | sparse = TRUE says how to enable it |
parallel solveODEBatch() |
a toolchain with OpenMP | correct results, conditions run serially |
The three are independent; cppODE() uses KLU without SUNDIALS. OpenMP
needs nothing installed on Linux or with Rtools; on macOS, Apple’s clang
needs libomp (brew install libomp).
Either install the libraries as system packages,
| Platform | SUNDIALS | SuiteSparse / KLU |
|---|---|---|
| Debian/Ubuntu | sudo apt install libsundials-dev |
sudo apt install libsuitesparse-dev |
| Fedora | sudo dnf install sundials-devel |
sudo dnf install suitesparse-devel |
| Arch | sudo pacman -S sundials |
sudo pacman -S suitesparse |
| macOS (Homebrew) | brew install sundials |
brew install suite-sparse |
or let cppDE build pinned releases into a per-user cache, which needs no administrator rights:
cppDE::install_libs("sundials") # or "suitesparse"./configure finds the cache on every install, so the build is needed
once. See ?install_libs for building during the install, build
options, and removing the cache. CPPDE_EXTRA_CXXFLAGS is appended to
the flags of every model compile().
To see what was detected:
writeLines(readLines(system.file("cvodeConfig.dcf", package = "cppDE")))- Fitting measured magnetisation dynamics: a Landau-Lifshitz-Gilbert model fitted to pump-probe measurements by Gauss-Newton on forward sensitivities, with a moving-average noise model and a multistart.
cppDE is distributed under the MIT License; see LICENSE /
LICENSE.md for the full text.
Portions of the C++ solver core in inst/include/cppde/ are derived
from third-party projects and remain subject to their upstream licenses:
- The Nordsieck multistep stepper (BDF/NDF and Adams-Moulton) in
cppde_multistepper.hpp,cppde_multistepper_controller.hppandcppde_newton.hppis a port of the corresponding routines in SUNDIALS/CVODE(S) (Copyright © 2002-2024 Lawrence Livermore National Security and Southern Methodist University), distributed under the BSD-3-Clause license. - The Rosenbrock4 stepper architecture in
cppde_rosenbrock4.hpp(and the surrounding stage-matrix, dense-output and stepper-protocol infrastructure) is derived from Boost.Numeric.Odeint by Karsten Ahnert, Mario Mulansky and Christoph Koke, distributed under the Boost Software License 1.0.
Full upstream copyright notices and license texts are reproduced in
inst/COPYRIGHTS. Both upstream licenses are
permissive and compatible with MIT; using or redistributing cppDE
requires preserving the notices in inst/COPYRIGHTS and the relevant
header attribution blocks.
The optional system libraries linked at run time are not vendored:
SUNDIALS (BSD-3-Clause) for the cvode() backend and SuiteSparse-KLU
(LGPL-2.1+) for the sparse-Jacobian path. Their own licenses govern the
libraries at the user’s installation site.