upd
This commit is contained in:
189
labs/lab1/code/main.py
Normal file
189
labs/lab1/code/main.py
Normal file
@@ -0,0 +1,189 @@
|
||||
import matplotlib.pyplot as plt
|
||||
import math
|
||||
import numpy as np
|
||||
from scipy.integrate import solve_ivp
|
||||
from scipy.optimize import fsolve
|
||||
|
||||
|
||||
class ODESolver:
|
||||
def euler_method(self, f, t_span, y0, h):
|
||||
t0, t_end = t_span
|
||||
N = int((t_end - t0) / h)
|
||||
t = np.linspace(t0, t_end, N + 1)
|
||||
y = np.zeros(N + 1)
|
||||
y[0] = y0
|
||||
|
||||
for i in range(N):
|
||||
y[i + 1] = y[i] + h * f(t[i], y[i])
|
||||
|
||||
return t, y
|
||||
|
||||
def explicit_trapezoid(self, f, t_span, y0, h):
|
||||
t0, t_end = t_span
|
||||
N = int((t_end - t0) / h)
|
||||
t = np.linspace(t0, t_end, N + 1)
|
||||
y = np.zeros(N + 1)
|
||||
y[0] = y0
|
||||
|
||||
for i in range(N):
|
||||
k1 = f(t[i], y[i])
|
||||
k2 = f(t[i] + h, y[i] + h * k1)
|
||||
y[i + 1] = y[i] + (h / 2) * (k1 + k2)
|
||||
|
||||
return t, y
|
||||
|
||||
def rk4_method(self, f, t_span, y0, h):
|
||||
t0, t_end = t_span
|
||||
N = int((t_end - t0) / h)
|
||||
t = np.linspace(t0, t_end, N + 1)
|
||||
y = np.zeros(N + 1)
|
||||
y[0] = y0
|
||||
|
||||
for i in range(N):
|
||||
k1 = f(t[i], y[i])
|
||||
k2 = f(t[i] + h/2, y[i] + h/2 * k1)
|
||||
k3 = f(t[i] + h/2, y[i] + h/2 * k2)
|
||||
k4 = f(t[i] + h, y[i] + h * k3)
|
||||
y[i + 1] = y[i] + h/6 * (k1 + 2*k2 + 2*k3 + k4)
|
||||
|
||||
return t, y
|
||||
|
||||
def backward_euler(self, f, t_span, y0, h):
|
||||
t0, t_end = t_span
|
||||
N = int((t_end - t0) / h)
|
||||
t = np.linspace(t0, t_end, N + 1)
|
||||
y = np.zeros(N + 1)
|
||||
y[0] = y0
|
||||
|
||||
for i in range(N):
|
||||
t_next = t[i + 1]
|
||||
|
||||
def equation(z):
|
||||
return z - h * f(t_next, z) - y[i]
|
||||
|
||||
y[i + 1] = fsolve(equation, y[i])[0]
|
||||
|
||||
return t, y
|
||||
|
||||
def implicit_trapezoid(self, f, t_span, y0, h):
|
||||
t0, t_end = t_span
|
||||
N = int((t_end - t0) / h)
|
||||
t = np.linspace(t0, t_end, N + 1)
|
||||
y = np.zeros(N + 1)
|
||||
y[0] = y0
|
||||
|
||||
for i in range(N):
|
||||
t_n = t[i]
|
||||
t_np1 = t[i + 1]
|
||||
y_n = y[i]
|
||||
|
||||
def equation(z):
|
||||
return z - y_n - (h/2) * (f(t_n, y_n) + f(t_np1, z))
|
||||
|
||||
y[i + 1] = fsolve(equation, y_n)[0]
|
||||
|
||||
return t, y
|
||||
|
||||
def problem_1_4():
|
||||
print("=== ЗАДАЧА 1.4: y' = y² - t, y(0) = 1 ===")
|
||||
|
||||
def f(t, y):
|
||||
return y**2 - t
|
||||
|
||||
t_span = [0, 1.0]
|
||||
y0 = 1
|
||||
h = 0.25
|
||||
|
||||
solver = ODESolver()
|
||||
|
||||
t_euler, y_euler = solver.euler_method(f, t_span, y0, h)
|
||||
t_trap, y_trap = solver.explicit_trapezoid(f, t_span, y0, h)
|
||||
t_rk4, y_rk4 = solver.rk4_method(f, t_span, y0, h)
|
||||
|
||||
sol_ref = solve_ivp(f, t_span, [y0], method='RK45',
|
||||
rtol=1e-10, atol=1e-12, dense_output=True)
|
||||
t_ref = np.linspace(t_span[0], t_span[1], 100)
|
||||
y_ref = sol_ref.sol(t_ref)[0]
|
||||
|
||||
y_ref_euler = sol_ref.sol(t_euler)[0]
|
||||
y_ref_trap = sol_ref.sol(t_trap)[0]
|
||||
y_ref_rk4 = sol_ref.sol(t_rk4)[0]
|
||||
|
||||
err_euler = np.linalg.norm(y_euler - y_ref_euler)
|
||||
err_trap = np.linalg.norm(y_trap - y_ref_trap)
|
||||
err_rk4 = np.linalg.norm(y_rk4 - y_ref_rk4)
|
||||
|
||||
print(f"Ошибка метода Эйлера: {err_euler:.2e}")
|
||||
print(f"Ошибка явного метода трапеций: {err_trap:.2e}")
|
||||
print(f"Ошибка метода РК4: {err_rk4:.2e}")
|
||||
|
||||
plt.figure(figsize=(12, 8))
|
||||
plt.plot(t_ref, y_ref, 'k-', linewidth=5, label='Эталонное решение (solve_ivp)')
|
||||
plt.plot(t_euler, y_euler, 'bo-', markersize=10, label='Метод Эйлера')
|
||||
plt.plot(t_trap, y_trap, 'c*-', markersize=15, label='Явный метод трапеций')
|
||||
plt.plot(t_rk4, y_rk4, 'rs-', markersize=5, label='Метод РК4')
|
||||
|
||||
plt.xlabel('t')
|
||||
plt.ylabel('y(t)')
|
||||
plt.title('Задача 1.4: y\' = y² - t, y(0) = 1')
|
||||
plt.legend()
|
||||
plt.grid(True, alpha=0.3)
|
||||
plt.show()
|
||||
|
||||
return t_euler, y_euler, t_trap, y_trap, t_rk4, y_rk4, t_ref, y_ref
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
result1 = problem_1_4()
|
||||
|
||||
def problem_2_4():
|
||||
print("\n=== ЗАДАЧА 2.4: y' = -2000y + t, y(0) = 0 ===")
|
||||
|
||||
def f(t, y):
|
||||
return -2000 * y + t
|
||||
|
||||
t_span = [0, 1]
|
||||
y0 = 0
|
||||
h = 1
|
||||
|
||||
solver = ODESolver()
|
||||
|
||||
t_euler, y_euler = solver.euler_method(f, t_span, y0, h)
|
||||
t_beuler, y_beuler = solver.backward_euler(f, t_span, y0, h)
|
||||
t_itrap, y_itrap = solver.implicit_trapezoid(f, t_span, y0, h)
|
||||
|
||||
sol_ref = solve_ivp(f, t_span, [y0], method='Radau',
|
||||
rtol=1e-10, atol=1e-12, dense_output=True)
|
||||
t_ref = np.linspace(t_span[0], t_span[1], 100)
|
||||
y_ref = sol_ref.sol(t_ref)[0]
|
||||
|
||||
y_ref_euler = sol_ref.sol(t_euler)[0]
|
||||
y_ref_beuler = sol_ref.sol(t_beuler)[0]
|
||||
y_ref_itrap = sol_ref.sol(t_itrap)[0]
|
||||
|
||||
err_euler = np.linalg.norm(y_euler - y_ref_euler)
|
||||
err_beuler = np.linalg.norm(y_beuler - y_ref_beuler)
|
||||
err_itrap = np.linalg.norm(y_itrap - y_ref_itrap)
|
||||
|
||||
print(f"Ошибка явного метода Эйлера: {err_euler:.2e}")
|
||||
print(f"Ошибка неявного метода Эйлера: {err_beuler:.2e}")
|
||||
print(f"Ошибка неявного метода трапеций: {err_itrap:.2e}")
|
||||
|
||||
plt.figure(figsize=(12, 8))
|
||||
plt.plot(t_ref, y_ref, 'k-', linewidth=5, label='Эталонное решение (solve_ivp)')
|
||||
plt.plot(t_euler, y_euler, 'bo-', markersize=4, label='Явный метод Эйлера')
|
||||
plt.plot(t_beuler, y_beuler, 'g^-', markersize=4, label='Неявный метод Эйлера')
|
||||
plt.plot(t_itrap, y_itrap, 'm*-',linewidth=2.2, markersize=4, label='Неявный метод трапеций')
|
||||
|
||||
plt.xlabel('t')
|
||||
plt.ylabel('y(t)')
|
||||
plt.title('Задача 2.4: y\' = -2000y + t, y(0) = 0 (жесткая система)')
|
||||
plt.legend()
|
||||
plt.grid(True, alpha=0.3)
|
||||
plt.show()
|
||||
|
||||
return t_euler, y_euler, t_beuler, y_beuler, t_itrap, y_itrap, t_ref, y_ref
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
result2 = problem_2_4()
|
||||
Reference in New Issue
Block a user