Skip to content

Commit 7dbc301

Browse files
ravi-ivar-7pre-commit-ci[bot]cclauss
authored
added rkf45 method (#10438)
* added rkf45 method * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Updated rkf45.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Updated rkf45.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update rkf45.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update rkf45.py with suggestions * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Improved Code Quality rkf45.py * Added more test cases and exception rkf45.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update rkf45.py * corrected some spellings. rkf45.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update rkf45.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update rkf45.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Christian Clauss <[email protected]>
1 parent 3ecad36 commit 7dbc301

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed

Diff for: maths/rkf45.py

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
"""
2+
Use the Runge-Kutta-Fehlberg method to solve Ordinary Differential Equations.
3+
"""
4+
5+
from collections.abc import Callable
6+
7+
import numpy as np
8+
9+
10+
def runge_futta_fehlberg_45(
11+
func: Callable,
12+
x_initial: float,
13+
y_initial: float,
14+
step_size: float,
15+
x_final: float,
16+
) -> np.ndarray:
17+
"""
18+
Solve an Ordinary Differential Equations using Runge-Kutta-Fehlberg Method (rkf45)
19+
of order 5.
20+
21+
https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta%E2%80%93Fehlberg_method
22+
23+
args:
24+
func: An ordinary differential equation (ODE) as function of x and y.
25+
x_initial: The initial value of x.
26+
y_initial: The initial value of y.
27+
step_size: The increment value of x.
28+
x_final: The final value of x.
29+
30+
Returns:
31+
Solution of y at each nodal point
32+
33+
# exact value of y[1] is tan(0.2) = 0.2027100937470787
34+
>>> def f(x, y):
35+
... return 1 + y**2
36+
>>> y = runge_futta_fehlberg_45(f, 0, 0, 0.2, 1)
37+
>>> y[1]
38+
0.2027100937470787
39+
>>> def f(x,y):
40+
... return x
41+
>>> y = runge_futta_fehlberg_45(f, -1, 0, 0.2, 0)
42+
>>> y[1]
43+
-0.18000000000000002
44+
>>> y = runge_futta_fehlberg_45(5, 0, 0, 0.1, 1)
45+
Traceback (most recent call last):
46+
...
47+
TypeError: 'int' object is not callable
48+
>>> def f(x, y):
49+
... return x + y
50+
>>> y = runge_futta_fehlberg_45(f, 0, 0, 0.2, -1)
51+
Traceback (most recent call last):
52+
...
53+
ValueError: The final value x must be greater than initial value of x.
54+
>>> def f(x, y):
55+
... return x
56+
>>> y = runge_futta_fehlberg_45(f, -1, 0, -0.2, 0)
57+
Traceback (most recent call last):
58+
...
59+
ValueError: Step size must be positive.
60+
"""
61+
if x_initial >= x_final:
62+
raise ValueError("The final value x must be greater than initial value of x.")
63+
64+
if step_size <= 0:
65+
raise ValueError("Step size must be positive.")
66+
67+
n = int((x_final - x_initial) / step_size)
68+
y = np.zeros(
69+
(n + 1),
70+
)
71+
x = np.zeros(n + 1)
72+
y[0] = y_initial
73+
x[0] = x_initial
74+
for i in range(n):
75+
k1 = step_size * func(x[i], y[i])
76+
k2 = step_size * func(x[i] + step_size / 4, y[i] + k1 / 4)
77+
k3 = step_size * func(
78+
x[i] + (3 / 8) * step_size, y[i] + (3 / 32) * k1 + (9 / 32) * k2
79+
)
80+
k4 = step_size * func(
81+
x[i] + (12 / 13) * step_size,
82+
y[i] + (1932 / 2197) * k1 - (7200 / 2197) * k2 + (7296 / 2197) * k3,
83+
)
84+
k5 = step_size * func(
85+
x[i] + step_size,
86+
y[i] + (439 / 216) * k1 - 8 * k2 + (3680 / 513) * k3 - (845 / 4104) * k4,
87+
)
88+
k6 = step_size * func(
89+
x[i] + step_size / 2,
90+
y[i]
91+
- (8 / 27) * k1
92+
+ 2 * k2
93+
- (3544 / 2565) * k3
94+
+ (1859 / 4104) * k4
95+
- (11 / 40) * k5,
96+
)
97+
y[i + 1] = (
98+
y[i]
99+
+ (16 / 135) * k1
100+
+ (6656 / 12825) * k3
101+
+ (28561 / 56430) * k4
102+
- (9 / 50) * k5
103+
+ (2 / 55) * k6
104+
)
105+
x[i + 1] = step_size + x[i]
106+
return y
107+
108+
109+
if __name__ == "__main__":
110+
import doctest
111+
112+
doctest.testmod()

0 commit comments

Comments
 (0)