Как сравнить метод Эйлера с методом Рунге-Кутты второго порядка на одном и том же шаге? - PullRequest
0 голосов
/ 28 апреля 2020

У меня есть два алгоритма для задачи численного дифференциального уравнения, один называется методом Эйлера, а второй называется Рунге Кутта второго порядка (RK2). По существу метод Эйлера и RK2 приближают решение дифференциальных уравнений. Единственное отличие состоит в том, что они используют разные формулы (Эйлер использует производную первого порядка ряда Тейлора, в то время как RK2 является производной второго порядка ряда Тейлора).

Я пытаюсь исправить некоторый написанный мной код чтобы он мог вернуть следующее решение, enter image description here

Однако мой код не возвращает правильные значения, когда дело доходит до RK2, но возвращает следующее,

enter image description here

Обратите внимание, что в моем решении размер шага h обозначается как dt. Я предоставил код, который использовал для создания этого ниже, а затем приведен числовой c пример метода Рунге Кутты второго порядка, который работает численно. Мне интересно показать, что с RK2 сходимость происходит быстрее, чем по методу Эйлера.

import matplotlib.pyplot as plt
import numpy as np
from math import exp  # exponential function

dy = lambda x, y: x * y
f = lambda x: exp(x ** 2 / 2)  # analytical solution function
x_final = 2

# analytical solution
x_a = np.arange(0, x_final, 0.01)
y_a = np.zeros(len(x_a))
for i in range(len(x_a)):
    y_a[i] = f(x_a[i])
plt.plot(x_a, y_a, label="analytical")

# Container for step sizes dt /dt
dt = 0.5

x = 0
y = 1
print("dt = " + str(dt))
print("x \t\t y (Euler) \t y (analytical)")
print("%f \t %f \t %f" % (x, y, f(x)))

n = int((x_final - x) / dt)

x_n = np.zeros(n + 1)
y_n = np.zeros(n + 1)
x_n[0] = x
y_n[0] = y

#Plot Euler's method
for i in range(n):
    y += dy(x, y) * dt
    x += dt
    print("%f \t %f \t %f" % (x, y, f(x)))
    x_n[i + 1] = x
    y_n[i + 1] = y

plt.plot(x_n, y_n, "x-", label="Euler dt=" + str(dt))

###################33
# Runge-Kutta's method 2'nd order (RK2)
x = 0
y = 1
print("dt = " + str(dt))
print("x \t\t y (rk2) \t y (analytical)")
print("%f \t %f \t %f" % (x, y, f(x)))

n = int((x_final - x) / dt)

x_n = np.zeros(n + 1)
y_n = np.zeros(n + 1)
x_n[0] = x
y_n[0] = y

# Plot the RK2
for z in range(n):
    K1 = dt*dy(x,y) # Step 1
    K2 = dt*dy(x+dt/2,y+K1/K2) # Step 2
    y += K2 # Step 3
    x += dt
    print("%f \t %f \t %f" % (x, y, f(x)))
    x_n[i + 1] = x
    y_n[i + 1] = y

plt.plot(x_n, y_n, "x-", label="RK2 dt=" + str(dt))

plt.title("Euler's method ")
plt.xlabel("x")
plt.ylabel("y")
plt.legend()
plt.show()

Это код с цифрой c, который работает для RK2. Я поместил шаг 1,2 и 3 в изменения метода Эйлера, который позволяет нам создать RK2.

from math import exp
dy = lambda x,y: x*y
f = lambda x: exp(x**2/2)
x = 0
xn = 2
y = 1
dt = 0.5
n = int((xn)/dt)
print ('x \t\t y (RK2) \t y (analytical)')
print ('%f \t %f \t %f'% (x,y,f(x)))
# main loop
for i in range(n):
    K1 = dt*dy(x, y) # step 1
    K2 = dt*dy(x + dt/2, y + K1/2) # step 2
    y += K2  # step 3
    x += dt
    print ('%f \t %f \t %f'% (x,y,f(x)))

Извините, если я задал этот вопрос плохо. Я новичок в python, поэтому я все еще пытаюсь понять, как go решать эти типы проблем. Вкратце мой вопрос состоит в том, как я могу исправить вышеуказанную функцию, чтобы вычислить правильную оценку и затем отобразить ее на графике, используя matplotlib из python.

1 Ответ

2 голосов
/ 28 апреля 2020

Есть две маленькие детали:

  1. В RK-2 l oop вы используете z, но для хранения значений вы используете i
  2. В исходной код, вы использовали y + K1 / K2 при обновлении K2, и это неправильно. Я вижу, вы исправили это во втором коде.

Итак, фиксированный код:

import matplotlib.pyplot as plt
import numpy as np
from math import exp  # exponential function

dy = lambda x, y: x * y
f = lambda x: exp(x ** 2 / 2)  # analytical solution function
x_final = 2

# analytical solution
x_a = np.arange(0, x_final, 0.01)
y_a = np.zeros(len(x_a))
for i in range(len(x_a)):
    y_a[i] = f(x_a[i])

plt.plot(x_a, y_a, label="analytical")

# Container for step sizes dt /dt
dt = 0.5

x = 0
y = 1
print("dt = " + str(dt))
print("x \t\t y (Euler) \t y (analytical)")
print("%f \t %f \t %f" % (x, y, f(x)))

n = int((x_final - x) / dt)

x_e = np.zeros(n + 1)
y_e = np.zeros(n + 1)
x_e[0] = x
y_e[0] = y

#Plot Euler's method
for i in range(n):
    y += dy(x, y) * dt
    x += dt
    print("%f \t %f \t %f" % (x, y, f(x)))
    x_e[i + 1] = x
    y_e[i + 1] = y

plt.plot(x_e, y_e, "x-", label="Euler dt=" + str(dt))

###################33
# Runge-Kutta's method 2'nd order (RK2)
x = 0
y = 1
print("dt = " + str(dt))
print("x \t\t y (rk2) \t y (analytical)")
print("%f \t %f \t %f" % (x, y, f(x)))

n = int((x_final - x) / dt)

x_r = np.zeros(n + 1)
y_r = np.zeros(n + 1)
x_r[0] = x
y_r[0] = y

# Plot the RK2
for i in range(n):
    K1 = dt*dy(x,y) # Step 1
    K2 = dt*dy(x+dt/2,y+K1/2) # Step 2
    y += K2 # Step 3
    x += dt
    print("%f \t %f \t %f" % (x, y, f(x)))
    x_r[i + 1] = x
    y_r[i + 1] = y

plt.plot(x_r, y_r, "s-", label="RK2 dt=" + str(dt))

plt.title("numerical differential equation problem")
plt.xlabel("x")
plt.ylabel("y")
plt.legend()
plt.show()
...