Metadata-Version: 2.4
Name: runge-kutta
Version: 0.1.2
Summary: Runge-Kutta ODE solvers
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: numpy

# Runge-Kutta ODE Solvers

Small Python implementations of classical fourth-order Runge-Kutta (RK4) and
Runge-Kutta-Fehlberg (RK45) methods for numerically solving ordinary
differential equations (ODEs).

The package is available on [PyPI](https://pypi.org/project/runge-kutta/).

## Requirements

- Python 3
- NumPy
- Matplotlib (for the example scripts)

Install the published package and its runtime dependency:

```bash
python -m pip install runge-kutta
```

For local development, install from a source checkout with
`python -m pip install .`.

## Usage

Import a solver from `runge_kutta`. Each function advances the solution by
one integration step for an equation of the form `dy/dt = f(t, y)`.

```python
import numpy as np
from runge_kutta import Derivative, State, rk4

def rhs(t: float, y: State) -> State:
    return -y

rhs: Derivative = rhs
t, y = rk4(rhs, t0=0.0, y0=np.array([1.0]), h=0.1)
```

### Types

The module provides these aliases for annotating equations and states:

```python
State = float | NDArray[np.float64]
Derivative = Callable[[float, State], State]
```

`State` represents either a scalar or a `float64` NumPy array. A
`Derivative` accepts a scalar time and a `State`, then returns the derivative
as a `State`.

### Solvers

| Function | Description | Returns |
| --- | --- | --- |
| `rk4(f, t0, y0, h)` | Performs one fixed-size classical fourth-order Runge-Kutta step. | `(t, y)` |
| `rk45(f, t0, y0, h)` | Performs one fixed-size Runge-Kutta-Fehlberg step using the fourth-order estimate. | `(t, y, error)` |
| `rk45_h_adj(f, t0, y0, h, epsilon)` | Performs an RK45 step and proposes a next step size from the embedded error estimate. | `(t, y, error, h_adj)` |

`f` must be a `Derivative`.

## Examples

The included scripts compare RK4 and RK45 while plotting solution trajectories
and RK45 error estimates:

```bash
python test1.py  # Lorenz system
python test2.py  # damped second-order system
```

Both scripts open Matplotlib windows. `test1.py` integrates the Lorenz system
for 500,000 steps and can take noticeably longer to run.
