만족스럽게 완료하지 못한 학교 프로젝트를 다시 검토하고 있습니다. 즉, 나는 거의 임의의 크기의 방정식 세트를 사용하여 반복적으로 해결하는 알고리즘을 작성했습니다. 문제는 "거의"부분입니다. 기본적으로 방정식이 두 개 이상 있어야하며 하나의 방정식으로 풀리지 않습니다. 위치 인수를 올바르게 사용하는 방법을 이해하지 못하기 때문입니다.
아래의 main 메소드에서 y_prime과 z_prime 두 가지 함수를 정의합니다. 둘 다 통과하면 내 솔루션에 대한 아름다운 그래프를 얻을 수 있습니다. 그러나 y_prime
초기 조건과 해 벡터 만 rungekutta()
함수에 전달하면 문제가 발생 합니다.
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
def rungekutta(dt, y, t, *funcs):
"""
The following code was written in order to
reproduce the classic 4th order Runge-Kutta numerical
method of solving a system of differential equations.
The aim was to not only apply this to the budworm deforestation
model developed by Ludwig et al, but also to create an algorithm
that is generic enough to accept a wide range of ODEs and
systems of ODEs.
:param dt: time step "Delta t"
:param y: The solution vector at the last time step
:param t: The time at the last time step
:param funcs: the vector field dy/dt = f(t,y)
:return: The solution vector for the next time step
"""
k1 = [dt * f(*y, t) for f in funcs]
args = [y_n + 0.5 * k_1 for y_n, k_1 in zip((*y, t), (*k1, dt))]
k2 = [dt * f(*args) for f in funcs]
args = [y_n + 0.5 * k_2 for y_n, k_2 in zip((*y, t), (*k2, dt))]
k3 = [dt * f(*args) for f in funcs]
args = [y_n + k_3 for y_n, k_3 in zip((*y, t), (*k3, dt))]
k4 = [dt * f(*args) for f in funcs]
return [y_n + (k_1 + 2 * k_2 + 2 * k_3 + k_4) / 6 for y_n, k_1, k_2, k_3, k_4 in
zip(y, k1, k2, k3, k4)]
if __name__ == '__main__':
def y_prime(y, z, t):
return -t * y
def z_prime(y, z, t):
return z
t_0 = -10
t_n = 10
dt = .05
steps = int((t_n - t_0) / dt)
y_soln = [0] * steps
z_soln = [0] * steps
time = np.arange(t_0, t_n, dt)
y_soln[0] = 1.928749848e-22
z_soln[0] = .0000453999297625
for i in np.arange(1, steps):
y_soln[i] = rungekutta(dt, y_soln[i-1], time[i-1], y_prime)
단일 방정식을 전달하려고 할 때받은 첫 번째 오류는 다음과 같습니다.
Traceback (most recent call last):
File "C:/Users/wesle/PycharmProjects/Budworms/RK4v2.py", line 57, in <module>
y_soln[i] = rungekutta(dt, y_soln[i-1], time[i-1], y_prime, z_prime)
File "C:/Users/wesle/PycharmProjects/Budworms/RK4v2.py", line 23, in rungekutta
k1 = [dt * f(*y, t) for f in funcs]
File "C:/Users/wesle/PycharmProjects/Budworms/RK4v2.py", line 23, in <listcomp>
k1 = [dt * f(*y, t) for f in funcs]
TypeError: y_prime() argument after * must be an iterable, not float
이것은 위치 인수로 "y_soln"이 있지만 이제는 하나만 있고 더 이상 반복 할 수 없기 때문입니다. 그래서 주 메서드에서 전달했을 때 1의 튜플로 만들었습니다.
for i in np.arange(1, steps):
y_soln[i] = rungekutta(dt, (y_soln[i-1],), time[i-1], y_prime)
하지만 지금은 내 y_prime 방정식에 튜플을 전달하고 있기 때문에 실제로 필요한 것은 float입니다.
Traceback (most recent call last):
File "C:/Users/wesle/PycharmProjects/Budworms/RK4v2.py", line 57, in <module>
y_soln[i] = rungekutta(dt, (y_soln[i-1],), time[i-1], y_prime)
File "C:/Users/wesle/PycharmProjects/Budworms/RK4v2.py", line 23, in rungekutta
k1 = [dt * f(*y, t) for f in funcs]
File "C:/Users/wesle/PycharmProjects/Budworms/RK4v2.py", line 23, in <listcomp>
k1 = [dt * f(*y, t) for f in funcs]
File "C:/Users/wesle/PycharmProjects/Budworms/RK4v2.py", line 38, in y_prime
return -t * y
TypeError: can't multiply sequence by non-int of type 'numpy.float64'
지금까지의 유일한 해결 방법은 내가 관심있는 방정식에 추가하여 $ y = y '$와 같은 추가 무작위 방정식을 푸는 것이 었습니다. 이것은 꽤 비효율적 인 것 같습니다.
그래서, 내가 그렇게하면 저주를 받고, 그렇지 않으면 저주받는 것처럼 보입니다. 이것에 대한 해결책이 있습니까?
편집 코드가 실제로 작동하는지 보려면 다음을 바꾸십시오.
for i in np.arange(1, steps):
y_soln[i] = rungekutta(dt, (y_soln[i-1],), time[i-1], y_prime)
두 방정식과 해 벡터를 함수에 전달하는 경우 :
for i in np.arange(1, steps):
y_soln[i], z_soln[i] = rungekutta(dt, (y_soln[i-1], z_soln[i-1]), time[i-1], y_prime, z_prime)
내 솔루션은 모든 목록을 numpy 배열로 변환하는 것이었고,이를 통해 기본 제공 요소 별 스칼라 덧셈 및 곱셈을 활용할 수있었습니다. 이로 인해 "k"값 계산이 훨씬 덜 번거롭고 복잡해졌습니다.
def rk4(dt, t, field, y_0):
"""
:param dt: float - the timestep
:param t: array - the time mesh
:param field: method - the vector field y' = f(t, y)
:param y_0: array - contains initial conditions
:return: ndarray - solution
"""
# Initialize solution matrix. Each row is the solution to the system
# for a given time step. Each column is the full solution for a single
# equation.
y = np.asarray(len(t) * [y_0])
for i in np.arange(len(t) - 1):
k1 = dt * field(t[i], y[i])
k2 = dt * field(t[i] + 0.5 * dt, y[i] + 0.5 * k1)
k3 = dt * field(t[i] + 0.5 * dt, y[i] + 0.5 * k2)
k4 = dt * field(t[i] + dt, y[i] + k3)
y[i + 1] = y[i] + (k1 + 2 * k2 + 2 * k3 + k4) / 6
return y
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다