Fast numerical ODE solvers (RK4, RK45, DOP853) optimized with Numba.
Project description
YENNEFER ODE SOLVER
Yennefer is a high-performance Python library for solving ordinary differential equations (ODEs), built on top of NumPy and accelerated via Numba JIT compilation.
Features
- Three integration methods covering fixed-step and adaptive workflows.
- Numba
@njit-compiled solver cores. - Unified, minimal API across all solvers.
- Pass arbitrary physical parameters to the RHS without global state.
- Works seamlessly with
@njit-decorated right-hand sides for maximum performance.
Installation
pip install yennefer
Solvers
| Class | Method | Order | Step control |
|---|---|---|---|
RK4Solver |
Classical Runge–Kutta | 4 | Fixed |
RK45Solver |
Runge–Kutta–Fehlberg 4(5) | 4/5 | Adaptive |
DOP853Solver |
Dormand–Prince 8(5,3) | 8 | Adaptive |
Example — Josephson Junction (RCSJ model)
The RCSJ model of a Josephson junction:
$$ \begin{cases} \frac{dV}{dt} = I_c + A\sin(u) - \beta V - \sin\varphi\ \frac{d\varphi}{dt} = V \ \frac{du}{dt} = \omega \end{cases} \tag{1} $$
import numpy as np
import matplotlib.pyplot as plt
from numba import njit
from yennefer import RK4Solver, RK45Solver, DOP853Solver
@njit
def jj_system(t, y, p):
V, ph, u = y
Ic, A, beta, omega = p[0], p[1], p[2], p[3]
return np.array([
Ic + A * np.sin(u) - beta * V - np.sin(ph),
V,
omega,
])
y0 = np.array([0.0, 0.0, 0.0])
params = np.array([0.1, 0.5, 0.2, 2.0]) # Ic, A, beta, omega
Fixed step with RK4
solver = RK4Solver(jj_system, y0, params)
T, Y = solver.solve(300.0, 5e-2)
Adaptive step with RK45
solver = RK45Solver(jj_system, y0, params)
T, Y = solver.solve(300.0, dt_initial=5e-2)
High-accuracy with DOP853
solver = DOP853Solver(jj_system, y0, params)
T, Y = solver.solve(300.0, dt_initial=5e-2)
Plot
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
ax1.plot(T, Y[:, 0], label="V(t)")
ax1.set_xlabel("t"); ax1.set_ylabel("V"); ax1.legend()
ax2.plot(T, Y[:, 1], label="φ(t)")
ax2.set_xlabel("t"); ax2.set_ylabel("φ"); ax2.legend()
plt.tight_layout()
plt.show()
More precise example is presented in example usage IPython notebook.
Another example is here.
RK4Solver — Fixed-Step 4th-Order Runge–Kutta
The classical RK4 method. Every step uses exactly 4 RHS evaluations. Best suited for smooth problems where you know the required step size in advance, or when uniform output is needed.
solver = RK4Solver(function, y0, params)
t, y = solver.solve(t_max, dt)
| Parameter | Description |
|---|---|
function |
RHS f(t, y, params) -> dy |
y0 |
Initial state vector (np.float64 array) |
params |
Parameter vector passed verbatim to f |
t_max |
Integration horizon |
dt |
Fixed step size |
RK45Solver — Adaptive Runge–Kutta–Fehlberg 4(5)
Embedded 4(5) pair with automatic step-size control. The 5th-order solution advances the state; the difference between 4th and 5th order estimates drives the error controller. 6 RHS evaluations per accepted step. Good general-purpose choice for moderate accuracy requirements.
solver = RK45Solver(function, y0, params, atol=1e-6, rtol=1e-3, max_step=np.inf)
t, y = solver.solve(t_max, dt_initial=1e-3)
| Parameter | Description |
|---|---|
atol |
Absolute error tolerance (default 1e-6) |
rtol |
Relative error tolerance (default 1e-3) |
max_step |
Maximum allowed step size (default ∞) |
dt_initial |
Initial step size guess |
DOP853Solver — Dormand–Prince 8(5,3)
Implementation of the classic Hairer–Nørsett–Wanner DOP853 method from Solving ODEs I (1993), based on the original Fortran source by Hairer & Williams. Dual embedded error estimators (5th and 3rd order), FSAL reuse (effectively 11 new RHS calls per accepted step). The go-to solver for high-accuracy and stiff-sensitive problems.
solver = DOP853Solver(function, y0, params, rtol=1e-9, atol=1e-9, n_max_steps=10000)
t, y = solver.solve(t_max, dt_init)
| Parameter | Description |
|---|---|
rtol |
Relative error tolerance (default 1e-9) |
atol |
Absolute error tolerance (default 1e-9) |
n_max_steps |
Maximum number of accepted steps (default 10000) |
dt_init |
Initial step size guess |
Common API
All solvers share the same RHS signature convention and output contract.
Right-hand side signature
@njit
def f(t: float, y: np.ndarray, params: np.ndarray) -> np.ndarray:
...
Decorating f with @njit is optional but strongly recommended — it eliminates the Python call overhead inside the inner loop and yields the best performance.
Output
solver.solve(...) returns a tuple (t, y):
| Name | Shape | Description |
|---|---|---|
t |
(N,) |
Time grid |
y |
(N, n_vars) |
Solution at each time point |
Both are also available as .t and .y properties after the call.
Performance tips
- Always decorate the RHS with
@njit. The first call triggers compilation (warm-up); subsequent calls run at native speed. - If you benchmark solvers against each other or against SciPy, run a short warm-up integration first to exclude JIT compilation time from the measurement.
- For adaptive solvers, tighter tolerances (
1e-12—1e-14) with DOP853 are often faster than the same accuracy with RK45, because DOP853 accepts far fewer steps.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file yennefer-0.5.0.tar.gz.
File metadata
- Download URL: yennefer-0.5.0.tar.gz
- Upload date:
- Size: 16.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
46a366e6f3170e1450f3c5aaaed151902458d8895ccf928add848e7c3a91cd4a
|
|
| MD5 |
1de862c6079cb67cc303f4e422df8128
|
|
| BLAKE2b-256 |
6b58395e3b662d3786296a4e9fd9d4c2939bed104369e707fad80b0d2675d87c
|
File details
Details for the file yennefer-0.5.0-py3-none-any.whl.
File metadata
- Download URL: yennefer-0.5.0-py3-none-any.whl
- Upload date:
- Size: 18.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6849f43f567e1eac299857f3811753434549d3c84ef3e9d36e58de9e2c372ef
|
|
| MD5 |
f68b804706cf3b251d0864607152e417
|
|
| BLAKE2b-256 |
2a669706cd69a9288878bc492b0d620a65052e0ab4c241104676d209387de852
|