main.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. # Решатель ОДУ методом Хёйна
  4. def solve_ode(start, end, step, max_calls, tolerance, fs, initial_conditions):
  5. """
  6. Решить систему ОДУ методом Хёйна.
  7. Параметры:
  8. start: начальное время
  9. end: конечное время
  10. step: начальный шаг интегрирования
  11. max_calls: максимальное количество вызовов функции fs
  12. tolerance: точность решения
  13. fs: функция-правая часть системы ОДУ
  14. initial_conditions: начальные условия
  15. """
  16. # Переменные для хранения времени и вектора решения
  17. t = start
  18. v = np.array(initial_conditions)
  19. # Счетчик вызовов функции fs
  20. call_counter = [0]
  21. # Вывести начальные значения
  22. print(f"{t_0:13.6f}{step:13.6f}{0:13d}{0:13d}", *[f"{x:12.6f}" for x in v])
  23. # Определение шага Хёйна
  24. def heun_step(t, v, h):
  25. """
  26. Вычислить шаг Хёйна.
  27. Параметры:
  28. t: текущее время
  29. v: текущее значение вектора решения
  30. h: шаг интегрирования
  31. """
  32. k1 = fs(t, v, call_counter)
  33. k2 = fs(t + h, v + h * k1, call_counter)
  34. return v + (h / 2) * (k1 + k2)
  35. # Цикл интегрирования
  36. while t < end and call_counter[0] < max_calls:
  37. # Вычислить коэффициенты Хёйна
  38. k1 = fs(t, v, call_counter)
  39. k2 = fs(t + step, v + step * k1, call_counter)
  40. v1 = v + (step / 2) * (k1 + k2)
  41. k2 = fs(t + step / 2, v + step / 2 * k1, call_counter)
  42. v2 = v + (step / 4) * (k1 + k2)
  43. # Вычислить следующий шаг Хёйна
  44. v2 = heun_step(t + step / 2, v2, step / 2)
  45. # Оценка ошибки
  46. error = np.linalg.norm(v2 - v1) / 3
  47. # Адаптация шага
  48. if error > tolerance:
  49. step /= 2
  50. elif error < tolerance / 64:
  51. step *= 2
  52. # Если ошибка приемлема, то сделать шаг и вывести решение
  53. if error < tolerance:
  54. if t + step > end:
  55. step = end - t
  56. t += step
  57. v = v1
  58. print(f"{t:13.6f} {step:13.6f} {error:13.5e} {call_counter[0]:13d}", *[f"{x:12.6f}" for x in v])
  59. if __name__ == "__main__":
  60. # Считать входные данные
  61. t_0 = float(input())
  62. T = float(input())
  63. h_0 = float(input())
  64. N_x = int(input())
  65. eps = float(input())
  66. n = int(input())
  67. # Считать код функции-правой части системы ОДУ
  68. function_code = []
  69. for _ in range(n + 3):
  70. line = input()
  71. function_code.append(line)
  72. # Определить функцию-правую часть системы ОДУ
  73. function_definition = "\n".join(function_code)
  74. exec(function_definition)
  75. # Считать начальные условия
  76. initial_conditions_str = input()
  77. initial_conditions = [float(x) for x in initial_conditions_str.split()]
  78. # Решить систему ОДУ
  79. solve_ode(t_0, T, h_0, N_x, eps, fs, initial_conditions)