runge-kutta 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- runge_kutta-0.1.0/PKG-INFO +64 -0
- runge_kutta-0.1.0/README.md +56 -0
- runge_kutta-0.1.0/pyproject.toml +14 -0
- runge_kutta-0.1.0/runge_kutta.egg-info/PKG-INFO +64 -0
- runge_kutta-0.1.0/runge_kutta.egg-info/SOURCES.txt +8 -0
- runge_kutta-0.1.0/runge_kutta.egg-info/dependency_links.txt +1 -0
- runge_kutta-0.1.0/runge_kutta.egg-info/requires.txt +1 -0
- runge_kutta-0.1.0/runge_kutta.egg-info/top_level.txt +1 -0
- runge_kutta-0.1.0/runge_kutta.py +116 -0
- runge_kutta-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: runge-kutta
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Runge-Kutta ODE solvers
|
|
5
|
+
Requires-Python: >=3.8
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: numpy
|
|
8
|
+
|
|
9
|
+
# Runge-Kutta ODE Solvers
|
|
10
|
+
|
|
11
|
+
Small Python implementations of classical fourth-order Runge-Kutta (RK4) and
|
|
12
|
+
Runge-Kutta-Fehlberg (RK45) methods for numerically solving ordinary
|
|
13
|
+
differential equations (ODEs).
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- Python 3
|
|
18
|
+
- NumPy
|
|
19
|
+
- Matplotlib (for the example scripts)
|
|
20
|
+
|
|
21
|
+
Install the module and its dependencies:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
python -m pip install .
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
Import a solver from `runge_kutta`. Each function advances the solution by
|
|
30
|
+
one integration step for an equation of the form `dy/dt = f(t, y)`.
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import numpy as np
|
|
34
|
+
from runge_kutta import rk4
|
|
35
|
+
|
|
36
|
+
def rhs(t, y):
|
|
37
|
+
return -y
|
|
38
|
+
|
|
39
|
+
t, y = rk4(rhs, t0=0.0, y0=np.array([1.0]), h=0.1)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Solvers
|
|
43
|
+
|
|
44
|
+
| Function | Description | Returns |
|
|
45
|
+
| --- | --- | --- |
|
|
46
|
+
| `rk4(f, t0, y0, h)` | Performs one fixed-size classical fourth-order Runge-Kutta step. | `(t, y)` |
|
|
47
|
+
| `rk45(f, t0, y0, h)` | Performs one fixed-size Runge-Kutta-Fehlberg step using the fourth-order estimate. | `(t, y, error)` |
|
|
48
|
+
| `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)` |
|
|
49
|
+
|
|
50
|
+
`f` must accept `(t, y)` and return the derivative at that point. `y` may be a
|
|
51
|
+
scalar or a NumPy array.
|
|
52
|
+
|
|
53
|
+
## Examples
|
|
54
|
+
|
|
55
|
+
The included scripts compare RK4 and RK45 while plotting solution trajectories
|
|
56
|
+
and RK45 error estimates:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
python test1.py # Lorenz system
|
|
60
|
+
python test2.py # damped second-order system
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Both scripts open Matplotlib windows. `test1.py` integrates the Lorenz system
|
|
64
|
+
for 500,000 steps and can take noticeably longer to run.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Runge-Kutta ODE Solvers
|
|
2
|
+
|
|
3
|
+
Small Python implementations of classical fourth-order Runge-Kutta (RK4) and
|
|
4
|
+
Runge-Kutta-Fehlberg (RK45) methods for numerically solving ordinary
|
|
5
|
+
differential equations (ODEs).
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Python 3
|
|
10
|
+
- NumPy
|
|
11
|
+
- Matplotlib (for the example scripts)
|
|
12
|
+
|
|
13
|
+
Install the module and its dependencies:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
python -m pip install .
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
Import a solver from `runge_kutta`. Each function advances the solution by
|
|
22
|
+
one integration step for an equation of the form `dy/dt = f(t, y)`.
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
import numpy as np
|
|
26
|
+
from runge_kutta import rk4
|
|
27
|
+
|
|
28
|
+
def rhs(t, y):
|
|
29
|
+
return -y
|
|
30
|
+
|
|
31
|
+
t, y = rk4(rhs, t0=0.0, y0=np.array([1.0]), h=0.1)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Solvers
|
|
35
|
+
|
|
36
|
+
| Function | Description | Returns |
|
|
37
|
+
| --- | --- | --- |
|
|
38
|
+
| `rk4(f, t0, y0, h)` | Performs one fixed-size classical fourth-order Runge-Kutta step. | `(t, y)` |
|
|
39
|
+
| `rk45(f, t0, y0, h)` | Performs one fixed-size Runge-Kutta-Fehlberg step using the fourth-order estimate. | `(t, y, error)` |
|
|
40
|
+
| `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)` |
|
|
41
|
+
|
|
42
|
+
`f` must accept `(t, y)` and return the derivative at that point. `y` may be a
|
|
43
|
+
scalar or a NumPy array.
|
|
44
|
+
|
|
45
|
+
## Examples
|
|
46
|
+
|
|
47
|
+
The included scripts compare RK4 and RK45 while plotting solution trajectories
|
|
48
|
+
and RK45 error estimates:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
python test1.py # Lorenz system
|
|
52
|
+
python test2.py # damped second-order system
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Both scripts open Matplotlib windows. `test1.py` integrates the Lorenz system
|
|
56
|
+
for 500,000 steps and can take noticeably longer to run.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "runge-kutta"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Runge-Kutta ODE solvers"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
dependencies = ["numpy"]
|
|
12
|
+
|
|
13
|
+
[tool.setuptools]
|
|
14
|
+
py-modules = ["runge_kutta"]
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: runge-kutta
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Runge-Kutta ODE solvers
|
|
5
|
+
Requires-Python: >=3.8
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: numpy
|
|
8
|
+
|
|
9
|
+
# Runge-Kutta ODE Solvers
|
|
10
|
+
|
|
11
|
+
Small Python implementations of classical fourth-order Runge-Kutta (RK4) and
|
|
12
|
+
Runge-Kutta-Fehlberg (RK45) methods for numerically solving ordinary
|
|
13
|
+
differential equations (ODEs).
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- Python 3
|
|
18
|
+
- NumPy
|
|
19
|
+
- Matplotlib (for the example scripts)
|
|
20
|
+
|
|
21
|
+
Install the module and its dependencies:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
python -m pip install .
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
Import a solver from `runge_kutta`. Each function advances the solution by
|
|
30
|
+
one integration step for an equation of the form `dy/dt = f(t, y)`.
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import numpy as np
|
|
34
|
+
from runge_kutta import rk4
|
|
35
|
+
|
|
36
|
+
def rhs(t, y):
|
|
37
|
+
return -y
|
|
38
|
+
|
|
39
|
+
t, y = rk4(rhs, t0=0.0, y0=np.array([1.0]), h=0.1)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Solvers
|
|
43
|
+
|
|
44
|
+
| Function | Description | Returns |
|
|
45
|
+
| --- | --- | --- |
|
|
46
|
+
| `rk4(f, t0, y0, h)` | Performs one fixed-size classical fourth-order Runge-Kutta step. | `(t, y)` |
|
|
47
|
+
| `rk45(f, t0, y0, h)` | Performs one fixed-size Runge-Kutta-Fehlberg step using the fourth-order estimate. | `(t, y, error)` |
|
|
48
|
+
| `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)` |
|
|
49
|
+
|
|
50
|
+
`f` must accept `(t, y)` and return the derivative at that point. `y` may be a
|
|
51
|
+
scalar or a NumPy array.
|
|
52
|
+
|
|
53
|
+
## Examples
|
|
54
|
+
|
|
55
|
+
The included scripts compare RK4 and RK45 while plotting solution trajectories
|
|
56
|
+
and RK45 error estimates:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
python test1.py # Lorenz system
|
|
60
|
+
python test2.py # damped second-order system
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Both scripts open Matplotlib windows. `test1.py` integrates the Lorenz system
|
|
64
|
+
for 500,000 steps and can take noticeably longer to run.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
numpy
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
runge_kutta
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
|
|
2
|
+
from numpy.linalg import norm
|
|
3
|
+
from numpy import inf
|
|
4
|
+
|
|
5
|
+
__all__ = ["rk4", "rk45", "rk45_h_adj"]
|
|
6
|
+
|
|
7
|
+
def rk4(f, t0, y0, h):
|
|
8
|
+
"""Advance an ordinary differential equation by one fourth-order RK step.
|
|
9
|
+
|
|
10
|
+
Solves ``dy/dt = f(t, y)`` from ``(t0, y0)`` using the classical
|
|
11
|
+
four-stage Runge-Kutta method and a fixed step size.
|
|
12
|
+
|
|
13
|
+
Parameters:
|
|
14
|
+
f : callable
|
|
15
|
+
Function defining the differential equation ``dy/dt = f(t, y)``.
|
|
16
|
+
t0 : float
|
|
17
|
+
The initial time.
|
|
18
|
+
y0 : float or numpy.ndarray
|
|
19
|
+
State at ``t0``.
|
|
20
|
+
h : float
|
|
21
|
+
Fixed integration step size.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
tuple[float, float or numpy.ndarray]
|
|
25
|
+
The time and state after one step.
|
|
26
|
+
"""
|
|
27
|
+
k1 = f(t0, y0)
|
|
28
|
+
k2 = f(t0 + (h/2), y0 + (h*k1/2))
|
|
29
|
+
k3 = f(t0 + (h/2), y0 + (h*k2/2))
|
|
30
|
+
k4 = f(t0 + h, y0 + (h*k3))
|
|
31
|
+
|
|
32
|
+
t = t0 + h
|
|
33
|
+
y = y0 + (h/6)*(k1 + 2*k2 + 2*k3 + k4)
|
|
34
|
+
|
|
35
|
+
return t, y
|
|
36
|
+
|
|
37
|
+
def rk45(f, t0, y0, h):
|
|
38
|
+
"""Advance an ODE by one fixed Runge-Kutta-Fehlberg (RK45) step.
|
|
39
|
+
|
|
40
|
+
Computes the fourth-order state estimate and the difference between the
|
|
41
|
+
embedded fourth- and fifth-order estimates, which callers can use for
|
|
42
|
+
local-error control.
|
|
43
|
+
|
|
44
|
+
Parameters:
|
|
45
|
+
f : callable
|
|
46
|
+
Function defining the differential equation ``dy/dt = f(t, y)``.
|
|
47
|
+
t0 : float
|
|
48
|
+
The initial time.
|
|
49
|
+
y0 : float or numpy.ndarray
|
|
50
|
+
State at ``t0``.
|
|
51
|
+
h : float
|
|
52
|
+
Fixed integration step size.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
tuple[float, float or numpy.ndarray, float or numpy.ndarray]
|
|
56
|
+
The time and fourth-order state estimate after one step, followed by
|
|
57
|
+
the embedded local-error estimate.
|
|
58
|
+
"""
|
|
59
|
+
k1 = f(t0, y0)
|
|
60
|
+
k2 = f(t0 + (h/4), y0 + (h*k1/4))
|
|
61
|
+
k3 = f(t0 + (3*h/8), y0 + (3*h*k1/32) + (9*h*k2/32))
|
|
62
|
+
k4 = f(t0 + (12*h/13), y0 + (1932*h*k1/2197) - (7200*h*k2/2197) + (7296*h*k3/2197))
|
|
63
|
+
k5 = f(t0 + h, y0 + (439*h*k1/216) - (8*h*k2) + (3680*h*k3/513) - (845*h*k4/4104))
|
|
64
|
+
k6 = f(t0 + (h/2), y0 - (8*h*k1/27) + (2*h*k2) - (3544*h*k3/2565) + (1859*h*k4/4104) - (11*h*k5/40))
|
|
65
|
+
|
|
66
|
+
t = t0 + h
|
|
67
|
+
y = y0 + h*((25*k1/216) + (1408*k3/2565) + (2197*k4/4104) - (1*k5/5))
|
|
68
|
+
error = h*((1*k1/360) - (128*k3/4275) - (2197*k4/75240) + (1*k5/50) + (2*k6/55))
|
|
69
|
+
|
|
70
|
+
return t, y, error
|
|
71
|
+
|
|
72
|
+
def rk45_h_adj(f, t0, y0, h, epsilon):
|
|
73
|
+
"""Perform an RK45 step and calculate an adjusted next step size.
|
|
74
|
+
|
|
75
|
+
The returned state is the fourth-order Runge-Kutta-Fehlberg estimate.
|
|
76
|
+
The proposed next step uses the infinity norm of the difference between
|
|
77
|
+
the embedded fourth- and fifth-order estimates and a safety factor of
|
|
78
|
+
0.84.
|
|
79
|
+
|
|
80
|
+
Parameters:
|
|
81
|
+
f : callable
|
|
82
|
+
Function defining the differential equation ``dy/dt = f(t, y)``.
|
|
83
|
+
t0 : float
|
|
84
|
+
The initial time.
|
|
85
|
+
y0 : float or numpy.ndarray
|
|
86
|
+
State at ``t0``.
|
|
87
|
+
h : float
|
|
88
|
+
Step size used for this integration step.
|
|
89
|
+
epsilon : float
|
|
90
|
+
Desired local-error tolerance used to calculate the next step size.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
tuple[float, float or numpy.ndarray, float or numpy.ndarray, float]
|
|
94
|
+
The time and fourth-order state estimate after one step, the embedded
|
|
95
|
+
local-error estimate, and the proposed step size for the next step.
|
|
96
|
+
"""
|
|
97
|
+
k1 = f( t0, y0 );
|
|
98
|
+
k2 = f( t0 + h/4, y0 + k1*h/4 );
|
|
99
|
+
k3 = f( t0 + 3*h/8, y0 + 3*k1*h/32 + 9*k2*h/32 );
|
|
100
|
+
k4 = f( t0 + 12*h/13, y0 + 1932*k1*h/2197 - 7200*k2*h/2197 + 7296*k3*h/2197 );
|
|
101
|
+
k5 = f( t0 + h, y0 + 439*k1*h/216 - 8*k2*h + 3680*k3*h/513 - 845*k4*h/4104 );
|
|
102
|
+
k6 = f( t0 + h/2, y0 - 8*k1*h/27 + 2*k2*h - 3544*k3*h/2565 + 1859*k4*h/4104 - 11*k5*h/40 );
|
|
103
|
+
|
|
104
|
+
# RK4
|
|
105
|
+
y_rk4 = y0 + h*( 25*k1/216 + 1408*k3/2565 + 2197*k4/4104 - k5/5 );
|
|
106
|
+
y_rk5 = y0 + h*( 16*k1/135 + 6656*k3/12825 + 28561*k4/56430 - 9*k5/50 + 2*k6/55 );
|
|
107
|
+
y = y_rk4;
|
|
108
|
+
t = t0 + h;
|
|
109
|
+
# estimativa do erro
|
|
110
|
+
error = h*( k1/360 - 128*k3/4275 - 2197*k4/75240 + k5/50 + 2*k6/55 );
|
|
111
|
+
# h ajustado
|
|
112
|
+
alpha = 0.84; # Segundo a ref.
|
|
113
|
+
p = 4; # RK order
|
|
114
|
+
h_adj = alpha*h*(epsilon*h/norm(y_rk5 - y_rk4, inf))**(1/p);
|
|
115
|
+
#
|
|
116
|
+
return t, y, error, h_adj
|