Files
Masterprojekt/runge_kutta.py
2026-02-11 12:08:46 +01:00

155 lines
4.6 KiB
Python

from typing import Callable
import numpy as np
from numpy.typing import NDArray
def rk4(ode: Callable, t0: float, v0: NDArray, weite: float, schritte: int, fein: bool = False) -> tuple[list, list]:
"""
Standard Runge-Kutta Verfahren 4. Ordnung
:param ode: ODE-System als Funktion
:param t0: Startwert der unabhängigen Variable
:param v0: Startwerte
:param weite: Integrationsweite
:param schritte: Schrittzahl
:param fein: Fein-Rechnung?
:return: Variable und Funktionswerte an jedem Stützpunkt
"""
h = weite/schritte
t_list = [t0]
werte = [v0]
for _ in range(schritte):
t = t_list[-1]
v = werte[-1]
if not fein:
v_next = rk4_step(ode, t, v, h)
else:
v_grob = rk4_step(ode, t, v, h)
v_half = rk4_step(ode, t, v, 0.5 * h)
v_fein = rk4_step(ode, t + 0.5 * h, v_half, 0.5 * h)
v_next = v_fein + (v_fein - v_grob) / 15.0
t_list.append(t + h)
werte.append(v_next)
return t_list, werte
def rk4_step(ode: Callable, t: float, v: NDArray, h: float) -> NDArray:
"""
Ein Schritt des Runge-Kutta Verfahrens 4. Ordnung
:param ode: ODE-System als Funktion
:param t: unabhängige Variable
:param v: abhängige Variablen
:param h: Schrittweite
:return: abhängige Variablen nach einem Schritt
"""
k1 = ode(t, v)
k2 = ode(t + 0.5 * h, v + 0.5 * h * k1)
k3 = ode(t + 0.5 * h, v + 0.5 * h * k2)
k4 = ode(t + h, v + h * k3)
return v + (h / 6.0) * (k1 + 2 * k2 + 2 * k3 + k4)
def rk4_end(ode: Callable, t0: float, v0: NDArray, weite: float, schritte: int, fein: bool = False):
"""
Standard Runge-Kutta Verfahren 4. Ordnung, nur Ausgabe der letzten Variablenwerte
:param ode: ODE-System als Funktion
:param t0: Startwert der unabhängigen Variable
:param v0: Startwerte
:param weite: Integrationsweite
:param schritte: Schrittzahl
:param fein: Fein-Rechnung?
:return: Variable und Funktionswerte am letzten Stützpunkt
"""
h = weite / schritte
t = float(t0)
v = np.array(v0, dtype=float, copy=True)
for _ in range(schritte):
if not fein:
v_next = rk4_step(ode, t, v, h)
else:
v_grob = rk4_step(ode, t, v, h)
v_half = rk4_step(ode, t, v, 0.5 * h)
v_fein = rk4_step(ode, t + 0.5 * h, v_half, 0.5 * h)
v_next = v_fein + (v_fein - v_grob) / 15.0
t += h
v = v_next
return t, v
# RK4 mit Simpson bzw. Trapez
def rk4_integral(ode: Callable, t0: float, v0: NDArray, weite: float, schritte: int, integrand_at: Callable, fein: bool = False, simpson: bool = True):
"""
Runge-Kutta Verfahren 4. Ordnung mit Simpson bzw. Trapez
:param ode: ODE-System als Funktion
:param t0: Startwert der unabhängigen Variable
:param v0: Startwerte
:param weite: Integrationsweite
:param integrand_at: Funktion
:param schritte: Schrittzahl
:param fein: Fein-Rechnung?
:param simpson: Simpson? Wenn nein, dann Trapez
:return: Variable und Funktionswerte am letzten Stützpunkt
"""
h = weite / schritte
habs = abs(h)
t = float(t0)
v = np.array(v0, dtype=float, copy=True)
if simpson and (schritte % 2 == 0):
f0 = float(integrand_at(t, v))
odd_sum = 0.0
even_sum = 0.0
fN = None
for i in range(1, schritte + 1):
if not fein:
v_next = rk4_step(ode, t, v, h)
else:
v_grob = rk4_step(ode, t, v, h)
v_half = rk4_step(ode, t, v, 0.5 * h)
v_fein = rk4_step(ode, t + 0.5 * h, v_half, 0.5 * h)
v_next = v_fein + (v_fein - v_grob) / 15.0
t += h
v = v_next
fi = float(integrand_at(t, v))
if i == schritte:
fN = fi
elif i % 2 == 1:
odd_sum += fi
else:
even_sum += fi
S = f0 + fN + 4.0 * odd_sum + 2.0 * even_sum
s = (habs / 3.0) * S
return t, v, s
f_prev = float(integrand_at(t, v))
acc = 0.0
for _ in range(schritte):
if not fein:
v_next = rk4_step(ode, t, v, h)
else:
v_grob = rk4_step(ode, t, v, h)
v_half = rk4_step(ode, t, v, 0.5 * h)
v_fein = rk4_step(ode, t + 0.5 * h, v_half, 0.5 * h)
v_next = v_fein + (v_fein - v_grob) / 15.0
t += h
v = v_next
f_cur = float(integrand_at(t, v))
acc += 0.5 * (f_prev + f_cur)
f_prev = f_cur
s = habs * acc
return t, v, s