Численное интегрирование обыкновенных дифференциальных уравнений
Решить краевую задачу для дифференциального уравнения второго порядка
с краевыми условиями первого рода: y(x0) = y0, y(x1) = y1 – на отрезке x ∈ [x0, x1].
Исходные данные:
Для наглядности дальнейших действий запишем общий вид дифференциального уравнения:
y'' + p(x)y' + q(x)y = f(x)
Теорию рекомендую почитать здесь (стр. 54 - 56)!
В процессе решения будет получена трехдиагональная СЛАУ, которую можно решить методом прогонки или методом Гаусса. В моем коде решение осуществляется методом Гаусса, т. к. он точнее.
Прежде чем запускать основной код, нужно сформировать код для метода Гаусса и проинициализировать его.
Вспомогательный код для решения СЛАУ методом Гаусса (подробнее в этой статье):
import numpy
def Metod_Gaussa(arr, brr):
for k in range(arr.shape[0] - 1):
#поиск строки с максимальным элементом
max_elem = 0
str = 0
for i in range (k, arr.shape[0]):
if abs(arr[i,k]) > abs(max_elem):
max_elem = arr[i,k]
str = i
#меняем местами строки квадратной матрицы
change = numpy.repeat(arr[k], 1)
arr[k], arr[str] = arr[str], change
#меняем местами элементы вектора-столбца
change = numpy.repeat(brr[k], 1)
brr[k], brr[str] = brr[str], change
#делим полученную строку на max_elem
arr[k] = arr[k] / max_elem
brr[k] = brr[k] / max_elem
#домножаем строку на коэффициенты и вычитаем ее из остальных строк
for i in range (k + 1, arr.shape[0]):
factor = arr[i,k]
arr[i] = arr[i] - arr[k] * factor
brr[i] = brr[i] - brr[k] * factor
#находим неизвестные
arg = [brr[brr.shape[0] - 1] / (arr[arr.shape[0] - 1, arr.shape[0] - 1])]
for i in range(arr.shape[0] - 2, -1, -1):
n = brr[i]
for j in range(len(arg)):
n = n - arg[j] * arr[i, arr.shape[0] - 1 - j]
arg.append(n)
#переворачиваем значения в списке
otv = []
for i in reversed(arg): otv.append(i)
return otv
Этот код следует добавить в отдельный файл в ту же папку PyCharm
, что и основной код:
Основной код:
import math
import numpy
import matplotlib.pyplot as plt
from Project1 import Gaussa
#задаем функции для дифференциального уравнения вида y" + py' + qy = f
def p(x): return -5
def q(x): return 6
def f(x): return math.exp((3 * x)) + x
x = [0, 3]
y = [2, 4]
n = 60 #число интервалов
def reshenie(p, q, f, x, y, n):
h = (x[1] - x[0]) / n #шаг
N = n - 1
A = numpy.zeros([N, N])
A[0, 0] = h ** 2 * q(x[0] + h) - 2
A[0, 1] = 1 + 0.5 * h * p(x[0] + h)
A[N - 1, N - 2] = 1 - 0.5 * h * p(x[1] - h)
A[N - 1, N - 1] = h ** 2 * q(x[1] - h) - 2
xi = x[0] + h
for i in range(1, N - 1):
xi += h
A[i, i - 1] = 1 - 0.5 * h * p(xi)
A[i, i] = h ** 2 * q(xi) - 2
A[i, i + 1] = 1 + 0.5 * h * p(xi)
B = numpy.zeros([N])
B[0] = h ** 2 * f(x[0] + h) - y[0] * (1 - 0.5 * h * p(x[0] + h))
B[N - 1] = h ** 2 * f(x[1] - h) - y[1] * (1 + 0.5 * h * p(x[1] - h))
xi = x[0] + h
global mas_xi
mas_xi = [xi]
for i in range(1, N - 1):
xi += h
mas_xi.append(xi)
B[i] = h ** 2 * f(xi)
mas_xi.append(x[1] - h)
#с помощью метода Гаусса находим yi
global yi
yi = []
for j in Gaussa.Metod_Gaussa(A, B):
yi.append(float(j))
point = [[] for i in range(len(yi))]
for i in range(len(yi)):
point[i].append(mas_xi[i])
point[i].append(yi[i])
return point
print(reshenie(p, q, f, x, y, n))
#график
mas_xi.insert(0, x[0]), yi.insert(0, y[0])
mas_xi.append(x[1]), yi.append(y[1])
plt.plot(mas_xi, yi)
plt.grid()
plt.show()
Результат:
Теперь разберемся с тем, что получили. Для этого рассмотрим пример попроще.
Далее применим тот же код, только в самом верху заменим параметры:
#задаем функции для дифференциального уравнения вида y" + py' + qy = f
def p(x): return x
def q(x): return -2
def f(x): return 2
x = [0, 4]
y = [0, 16]
Результат - парабола, что и следовало ожидать: