CyRK
Runge-Kutta ODE Integrator Implemented in Cython and Numba
Install / Use
/learn @jrenaud90/CyRKREADME
CyRK
<div style="text-align: center;"> <a href="https://doi.org/10.5281/zenodo.7093266"><img src="https://zenodo.org/badge/DOI/10.5281/zenodo.7093266.svg" alt="DOI"></a> <a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/Python-3.9|3.10|3.11|3.12|3.13-blue" alt="Python Version 3.9-3.14" /></a> <!-- <a href="https://codecov.io/gh/jrenaud90/CyRK" ><img src="https://codecov.io/gh/jrenaud90/CyRK/branch/main/graph/badge.svg?token=MK2PqcNGET" alt="Code Coverage"/></a> --> <br /> <a href="https://github.com/jrenaud90/CyRK/actions/workflows/push_tests_win.yml"><img src="https://github.com/jrenaud90/CyRK/actions/workflows/push_tests_win.yml/badge.svg?branch=main" alt="Windows Tests" /></a> <a href="https://github.com/jrenaud90/CyRK/actions/workflows/push_tests_mac.yml"><img src="https://github.com/jrenaud90/CyRK/actions/workflows/push_tests_mac.yml/badge.svg?branch=main" alt="MacOS Tests" /></a> <a href="https://github.com/jrenaud90/CyRK/actions/workflows/push_tests_ubun.yml"><img src="https://github.com/jrenaud90/CyRK/actions/workflows/push_tests_ubun.yml/badge.svg?branch=main" alt="Ubuntu Tests" /></a> <a href="https://app.readthedocs.org/projects/cyrk/builds/?version__slug=latest"><img src="https://app.readthedocs.org/projects/cyrk/badge/?version=latest&style=flat" alt="Ubuntu Tests" /></a> <br /> <a href="https://pypi.org/project/CyRK/"><img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/CyRK?label=PyPI%20Downloads" /></a> <a href="https://anaconda.org/conda-forge/cyrk"> <img alt="Conda Downloads" src="https://img.shields.io/conda/d/conda-forge/cyrk" /> </a> </div><a href="https://github.com/jrenaud90/CyRK/releases"><img src="https://img.shields.io/badge/CyRK-0.17.0 Alpha-orange" alt="CyRK Version 0.17.0 Alpha" /></a>
Runge-Kutta ODE Integrator Implemented in Cython and Numba
<img style="text-align: center" src="https://github.com/jrenaud90/CyRK/blob/main/Benchmarks/CyRK_SciPy_Compare_predprey_v0-17-0.png" alt="CyRK Performance Graphic" />CyRK provides fast integration tools to solve systems of ODEs using an adaptive time stepping scheme. CyRK can accept differential equations that are written in pure Python, njited numba, or cython-based cdef. Implementing these types of functions is generally easier than doing so in pure C. Calling CyRK's functions and utilizing its results is also much easier to integrate into existing Python or Cython software. Using CyRK can speed up development time while avoiding the slow performance that comes with using pure Python-based solvers like SciPy's solve_ivp.
The purpose of this package is to provide some functionality of scipy's solve_ivp with greatly improved performance.
Currently, CyRK's numba-based (njit-safe) implementation is 8--60x faster than scipy's solve_ivp function.
The cython-based pysolve_ivp function that works with python (or njit'd) functions is 10-40x faster than scipy.
The cython-based cysolver_ivp function that works with cython-based cdef functions is 100-500x faster than scipy.
Details about CyRK's performance including more benchmarks can be found here.
CyRK's solvers can also be parallelized for even larger gains.
An additional benefit of the two cython implementations is that they are pre-compiled. This avoids most of the start-up performance hit experienced by just-in-time compilers like numba.
Overview
Supported Features
CyRK's pysolve_ivp (which works with pure python functions) and cysolve_ivp (which works with cython compiled functions) shares many of the same features as SciPy's solve_ivp:
- Triggerable events to track certain events or cause a early termination.
- Adaptive step size solver that uses relative and absolute error of the ODE to increase or decrease the step size as needed.
- Dense output to create callable functions to interpolate an ODE's solution between solution steps. Allowing user to take advantage of the much more efficient adaptive step size solver.
- A user-provided time domain or
t_evalcan be given to the solver to find solutions at specific time steps.
Note: nbsolve_ivp has a much more limited feature set than cysolve_ivp and pysolve_ivp. The latter methods are recommended where possible.
Supported Integrators
Currently, CyRK supports the following integration methods:
- "RK23" - Explicit Runge-Kutta method of order 3(2).
- "RK45" - Explicit Runge-Kutta method of order 5(4)
- "DOP853" - Explicit Runge-Kutta method of order 8. Error is controlled using a combination of 5th and 3rd order interpolators.
More methods will be added as the need arises. We are always looking for contributors if you'd like to see your favorite method added to CyRK!
Additional Features
In additional to improved performance, CyRK offers a few additional features that SciPy does not:
- Ability to capture extra outputs during integration so a user can record other parameters instead of just the dependent variables without having to make repeat calls to the differential equations.
- Ability to reuse solvers when the previous result is no longer needed or has been recorded (improving performance, particularly for problems with small integration domain sizes).
- CyRK provides a robust integration diagnostic feedback system to identify and help remedy issues with an ODE solution.
- CyRK offers much more control over the memory management and other aspects of the solver.
Limitations
There are some features that SciPy has that CyRK currently does not. A non-exhaustive list is:
- A number of integrator methods are missing, particularly implicit approaches.
cysolve_ivpandpysolve_ivpcan only work with ODEs of double-precision floating point numbers. So complex numbers are not directly supported but systems of ODEs of complex numbers can be converted to systems of doubles for use with CyRK.
Installation
CyRK has been tested on Python 3.9--3.14; Windows, Ubuntu, and MacOS.
Install via pip:
pip install CyRK
conda:
conda install -c conda-forge CyRK
mamba:
mamba install cyrk
If not installing from a wheel, CyRK will attempt to install Cython and Numpy in order to compile the source code. A "C++ 20" compatible compiler is required.
Compiling CyRK has been tested on the latest versions of Windows, Ubuntu, and MacOS. Your milage may vary if you are using an older or different operating system.
If on MacOS you will likely need a non-default compiler in order to compile the required OpenMP package. See the "Installation Troubleshooting" section below.
After everything has been compiled, cython will be uninstalled and CyRK's runtime dependencies (see the pyproject.toml file for the latest list) will be installed instead.
A new installation of CyRK can be tested quickly by running the following from a python console.
from CyRK import test_pysolver, test_cysolver, test_nbrk
test_pysolver()
# Should see "CyRK's PySolver was tested successfully."
test_cysolver()
# Should see "CyRK's CySolver was tested successfully."
test_nbrk()
# Should see "CyRK's nbrk_ode was tested successfully."
Installation Troubleshooting
Please report installation issues. We will work on a fix and/or add workaround information here.
-
If you see a "Can not load module: CyRK.cy" or similar error then the cython extensions likely did not compile during installation. Try running
pip install CyRK --no-binary="CyRK"to force python to recompile the cython extensions locally (rather than via a prebuilt wheel). -
On MacOS: If you run into problems installing CyRK then reinstall using the verbose flag (
pip install -v .) to look at the installation log. If you see an error that looks like "clang: error: unsupported option '-fopenmp'" then you are likely using the default compiler or other compiler that does not support OpenMP. Read more about this issue here and the steps taken here. A fix for this issue is to usellvm's clang compiler. This can be done by doing the following in your terminal before installing CyRK.
brew install llvm
brew install libomp
# If on a newer computer that uses ARM64 (Apple Silicon) then:
export LDFLAGS="-L/opt/homebrew/opt/llvm/lib"
export CPPFLAGS="-I/opt/homebrew/opt/llvm/include"
export LDFLAGS="-L/opt/homebrew/opt/libomp/lib"
export CPPFLAGS="-I/opt/homebrew/opt/libomp/include"
export CC=/opt/homebrew/opt/llvm/bin/clang
export CXX=/opt/homebrew/opt/llvm/bin/clang++
# Otherwise change these directories to:
export LDFLAGS="-L/usr/local/opt/llvm/lib"
export CPPFLAGS="-I/usr/local/opt/llvm/include"
export LDFLAGS="-L/usr/local/opt/libomp/lib"
export CPPFLAGS="-I/usr/local/opt/libomp/include"
export CC=/usr/local/opt/llvm/bin/clang
export CXX=/usr/local/opt/llvm/bin/clang++
pip install CyRK --no-binary="CyRK"
- CyRK has a number of runtime status codes which can be used to help determine what failed during integration. Learn more about these codes https://cyrk.readthedocs.io/en/latest/Status_and_Error_Codes.html.
Development and Testing Dependencies
If you inten
