С Новым годом! Форум программистов, компьютерный форум, киберфорум
Python: Научные вычисления
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/4: Рейтинг темы: голосов - 4, средняя оценка - 4.75
8 / 6 / 2
Регистрация: 03.05.2016
Сообщений: 242

Ошибка с импортом методов классов для численного решения ОДУ 5 порядка

20.05.2022, 20:25. Показов 777. Ответов 2

Студворк — интернет-сервис помощи студентам
Коллеги, уважаемые форумчане, привествую! Возникла в общем проблема следующего характера. Пробую написать так чказать программу решатель ОДУ 5 порядка, используя принципы ООП. Ноебходимо реализовать несколько численных схем решения, чтобы потом можно было решать ОДУ и сравнить результаты решения.

Каждая из численных схем реализована в виде отдельного класса, который наследует методы суперкласса ODE_Solver - по сути в нем осуществляется проверка, что передаваемая функция (правая часть уравнения является вектором или скаляром, также прописан сам цикл прохода по узлам, в которых отыскивается решение ОДУ. Каждя численная схема реализована в виде класса, при этом, содежит только метод solve_st. В качетсве примера рассмотрим реализацию прямой схемы Эйлера для решения ОДУ 5 степени с начальными условиями y0.

Ниже представлена реализация класса ODE_Solver
ODS.py


Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import numpy as np
 
 
class ODE_Solver(object):
    """
    Суперкласс для решения ОДУ или системы ОДУ нормированной и приведенной к виду: du/dx = f(u, x)
    Атрибуты класса:
    x: массив узлов точек координаты x
    u: массив решения ОДУ в точках узла x
    k: число шагов вычисления значения в узлах
    f: функция правой части ОДУ, реализованная в виде: f(u, x)
    """
 
 
    def __init__(self, f):
        if not callable(f):
            # проверка корректности типа передаваемой функции f(u, x)
            raise TypeError('f не %s, является функцией' % type(f))
        # результат работы вычисления функции решателя (тип float)
        self.f = lambda u, x: np.asarray(f(u, x), float)
 
    def solver_st(self):
        """Реализация численной схемы решателя"""
        FE.solver_st(self)
        raise NotImplementedError
 
    def set_initial_condition(self, u0):
        if isinstance(u0, (float, int)):  # ОДУ является одномерным
            self.neq = 1
            u0 = float(u0)
        else:  # система ОДУ, ОДУ порядка выше 1-го
            u0 = np.asarray(u0)  # (начальные условия вектор-функция - порядок 2+)
            self.neq = u0.size
        self.u0 = u0
 
        # Проверка, что функция возвращает вектор f корректной длины:
        try:
            f0 = self.f(self.u0, 0)
        except IndexError:
            raise IndexError(
                'Индекс вектора u выходит за границы f(u,x). Допустимые индексы %s' % (str(range(self.neq))))
        if f0.size != self.neq:
            raise ValueError('f(u,x) возвращено %d элементов, вектор u имеет %d элементов' % (f0.size, self.neq))
 
    def solve(self, coord_points, terminate=None):
        """
        Решение ОДУ и  запись полученных значений в виде массива или списка.
        По умолчанию функция возвращает False, если нет элементов.
        """
        if terminate is None:
            terminate = lambda u, x, step_no: False
 
        if isinstance(coord_points, (float, int)):
            raise TypeError('solve: массив точек x не является итерируемым объектом')
        self.x = np.asarray(coord_points)
        if self.x.size <= 1:
            raise ValueError('ODESolver.solve требует на вход массив координат'
                             ' точек поиска решения. Число точек меньше 2!')
 
        n = self.x.size
        if self.neq == 1:  # ОДУ
            self.u = np.zeros(n)
        else:  # ОДУ порядка 2+ или система ОДУ
            self.u = np.zeros((n, self.neq))
 
        # Присвоить self.x[0] corresponds to self.u0
        self.u[0] = self.u0
 
        # Проход по сетке координат x (использование векторизации)
        for k in range(n - 1):
            self.k = k
            self.u[k + 1] = self.solver_st()
            if terminate(self.u, self.x, self.k + 1):
                break  # прервать цикл при последнем k
        return self.u[:k + 2], self.x[:k + 2]


Непосредственно реализация класса численной схемы Эйлера FE
ES.py

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from abc import ABC
from ODS import ODE_Solver
 
 
class FE(ODE_Solver, ABC):
    """
    Реализация классической прямой схемы Эйлера первого порядка точности.
    Возвращает массив решения ОДУ или системы ОДУ.
    Атрибуты класса:
    x: массив узлов точек координаты x
    u: массив решения ОДУ в точках узла x
    k: число шагов вычисления значения в узлах
    f: функция правой части ОДУ, реализованная в виде: f(u, x)
    """
 
    x = None
    k = None
    f = None
    u = None
 
    @classmethod
    def solver_st(self):
        u, f, k, x = self.u, self.f, self.k, self.x
        dx = x[k+1] - x[k]
        u_new = u[k] + dx*f(u[k], x[k])
        return u_new


Непосрественно пытаюсь вызвать теперь схему решателя и передать в нее ОДУ пятого порядка def f(u,x):
test.py

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import matplotlib.pyplot as plt
import numpy as np
from ODS import ODE_Solver
 
# само дифференциальное уравнение 
def f(u, x):
    return (u[1],
            u[2],
            u[3],
            u[4],
            - 15 * u[4] - 90 * u[3] -
            270 * u[2] - 405 * u[1] - 243 * u[0])
 
 
y0 = [0, 3, -9, -8, 0]
solver = ODE_Solver.solver_st(f)
solver.set_initial_condition(y0)
x_points = np.linspace(0, 5, 150)
u, x = solver.solve(x_points)
plt.plot(x, u)


Исходная задача:

https://www.cyberforum.ru/cgi-bin/latex.cgi?\frac{d^{5}y}{dx^{5}} + 15\frac{d^{4}y}{dx^{4}} + 90\frac{d^{3}y}{dx^{3}}+ 270\frac{d^{2}y}{dx^{2}}+ 405\frac{dy}{dx} + 243y = 0

https://www.cyberforum.ru/cgi-bin/latex.cgi?y\mid_{x=0} = 0; \qquad \frac{dy}{dx}\mid_{x=0} = 3; \qquad \frac{d^{2}y}{dx^{2}}\mid_{x=0} = -9;  \qquad \frac{d^{3}y}{dx^{3}}\mid_{x=0} = -8; \qquad \frac{d^{4}y}{dx^{4}}\mid_{x=0} = 0;


При вызове требуемой схемы решателя я получаю странную ошибку следующего типа:

Code
1
2
3
4
5
6
7
8
Traceback (most recent call last):
  File "C:\Fin_Proj_ODE\test1.py", line 3, in <module>
    from ODS import ODE_Solver
  File "C:\Fin_Proj_ODE\ODS.py", line 3, in <module>
    from ES import FE
  File "C:\Fin_Proj_ODE\ES.py", line 2, in <module>
    from ODS import ODE_Solver
ImportError: cannot import name 'ODE_Solver' from partially initialized module 'ODS' (most likely due to a circular import) (C:\Fin_Proj_ODE\ODS.py)
Уважаемые форумчане, мне очень нужна Ваша помощь и есть несколько вопросов:

1) Каким образом решить подобную ошибку, потому что я не понимаю, как исправить цикличную ссылку при попытке подключения фйла с классом и методами класса?

2) Каким образом можно реализовать класс Problem с исходной задачей и передавать требуемые аргументы, а также вернуть массив погрешности работы решателя?

3) Насколько правильно в данном случае реализованы остальные методы решателя?

RKS.py

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from abc import ABC
from ODS import ODE_Solver
 
 
class RK4(ODE_Solver, ABC):
    """
    Реализация классической схемы Рунге-Кутта 4 порядка. Является наиболее стабильной
    неадаптивной многошаговой схемой 4 порядка точности. Явная реализация схемы.
    Возвращает массив решения ОДУ или системы ОДУ.
    Атрибуты класса:
    x: массив узлов точек координаты x
    u: массив решения ОДУ в точках узла x
    k: число шагов вычисления значения в узлах
    f: функция правой части ОДУ, реализованная в виде: f(u, x)
    """
    def solver_st(self):
        u, f, k, x = self.u, self.f, self.k, self.x
        dx = x[k+1] - x[k]
        dx2 = dx/2.0
        K1 = dx*f(u[k], x[k])
        K2 = dx*f(u[k] + 0.5*K1, x[k] + dx2)
        K3 = dx*f(u[k] + 0.5*K2, x[k] + dx2)
        K4 = dx*f(u[k] + K3, x[k] + dx)
        u_new = u[k] + (1/6.0)*(K1 + 2*K2 + 2*K3 + K4)
        return u_new


RKFS.py

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from abc import ABC
from ODS import ODE_Solver
import numpy as np
 
 
class RKF(ODE_Solver, ABC):
    """
    Реализация  Рунге-Кутта-Фельберга 4 порядка точности (модификация метода Рунге-Кутта с адаптивным шагом)
    Возвращает массив решения ОДУ или системы ОДУ.
    Атрибуты класса:
    x: массив узлов точек координаты x
    u: массив решения ОДУ в точках узла x
    k: число шагов вычисления значения в узлах
    f: функция правой части ОДУ, реализованная в виде: f(u, x)
    """
 
    def __init__(self, f):
        super().__init__(f)
        self.tol = None
        self.coeff_err = None
        self.beta = None
        self.coeff = None
        self.alpha = None
        self.coeff_star = None
        self.coeff_err = None
        self.alpha = None
 
    def solver_st(self):
        u, f, k, x, alpha, beta, coeff, coeff_star, coeff_err, tol = self.u, self.f, self.k, self.alpha, self.x, \
                                                     self.beta, self.coeff, self.coeff_star, self.tol, self.coeff_err
 
        # Таблица Бутчера коэффициентов схемы Рунге-Кутта 4 порядка и 5 порядка точности.
        alpha = np.array([0.0, 1.0 / 4.0, 3.0 / 8.0, 12.0 / 13.0, 1.0, 1.0 / 2.0])
        beta = np.array([[0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
                         [1.0 / 4.0, 0.0, 0.0, 0.0, 0.0, 0.0],
                         [3.0 / 32.0, 9.0 / 32.0, 0.0, 0.0, 0.0, 0.0],
                         [1932.0 / 2197.0, (-7200.0) / 2197.0, 7296.0 / 2197.0, 0.0, 0.0, 0.0],
                         [439.0 / 216.0, -8.0, 3680.0 / 513.0, (-845.0) / 4104.0, 0.0, 0.0],
                         [(-8.0) / 27.0, 2.0, (-3544.0) / 2565.0, 1859.0 / 4104.0, (-11.0) / 40.0, 0.0]])
        coeff = np.array(
            [25.0 / 216.0, 0.0, 1408.0 / 2565.0, 2197.0 / 4104.0, (-1.0) / 5.0, 0.0])
        # коэффициенты 4 порядка точности
        coeff_star = np.array([16.0 / 135.0, 0.0, 6656.0 / 12825.0, 28561.0 / 56430.0, (-9.0) / 50.0,
                               2.0 / 55.0])  # коэффициенты 5 порядка точности
        
        coeff_err = coeff - coeff_star  # разность коэффициентов методов 4 и 5 порядка
        dx = x[k + 1] - x[k] # начальное приближение адаптивного шага решателя
 
        K1 = dx*f(u[k],x[k])
        K2 = f(u[k] + dx * beta[1, 0] * K1)
        K3 = f(u[k] + dx * (beta[2, 0] * K1 + beta[2, 1] * K2))
        K4 = f(u[k] + dx * (beta[3, 0] * K1 + beta[3, 1] * K2 + beta[3, 2] * K3))
        K5 = f(u[k] + dx * (beta[4, 0] * K1 + beta[4, 1] * K2 + beta[4, 2] * K3 + beta[4, 3] * K4))
        K6 = f(u[k] + dx * (beta[5, 0] * K1 + beta[5, 1] * K2 + beta[5, 2] * K3 + beta[5, 3] * K4 + beta[5, 4] * K5))
        errorfield = dx * (coeff_err[0] * K1 + coeff_err[1] * K2 + coeff_err[2] * K3 + coeff_err[3] * K4 +
                           coeff_err[4] * K5 + coeff_err[5] * K6)
        max_error = np.absolute(errorfield).max()
 
        if max_error <= tol:
            u[k+1] = u[k] + dx * ( coeff_star[0] * K1 + coeff_star[1] * K2 + coeff_star[2] * K3 +
                                   coeff_star[3] * K4 + coeff_star[4] * K5 + coeff_star[5] * K6)
            dxx = dx* (tol / max_error) ** 0.2
            dx = dxx
            x[k+1] = x[k] + dx
            eps = max_error
        else:
            dx = dx * (tol / max_error) ** 0.25
        u_new = u[k]
        return u_new, eps


ADS.py

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from abc import ABC
from ODS import ODE_Solver
 
 
class ABF4(ODE_Solver, ABC):
    """
    Реализация классической 4-х шаговой схемы Адамса-Башфорта. Явная реализация схемы.
    Возвращает массив решения ОДУ или системы ОДУ.
    Атрибуты класса:
    x: массив узлов точек координаты x
    u: массив решения ОДУ в точках узла x
    k: число шагов вычисления значения в узлах
    f: функция правой части ОДУ, реализованная в виде: f(u, x)
    """
 
    def solver_st(self):
        u, f, k, x = self.u, self.f, self.k, self.x
        dx = x[k + 1] - x[k]
        dx2 = dx / 2.0
        K1 = dx * f(u[k], x[k])
        K2 = dx * f(u[k] + 0.5 * K1, x[k] + dx2)
        K3 = dx * f(u[k] + 0.5 * K2, x[k] + dx2)
        K4 = dx * f(u[k] + K3, x[k] + dx)
        u = u[k] + (1 / 6.0) * (K1 + 2 * K2 + 2 * K3 + K4)
 
        u_new = (u[-1] + (dx / 24) * (55 * f(x[-1], u[-1]) - 59 * f(x[-2], u[-2])
                                      + 37 * f(x[-3], u[-3]) - 9 * f(x[-4], u[-4])))
        # x = (x[-1] + dx)
        return u_new


AMS.py

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from abc import ABC
from ODS import ODE_Solver
 
 
class AM4(ODE_Solver, ABC):
    """
    Реализация классической 4-х шаговой схемы Адамса-Моултона. Явная реализация схемы.
    Возвращает массив решения ОДУ или системы ОДУ.
    Атрибуты класса:
    x: массив узлов точек координаты x
    u: массив решения ОДУ в точках узла x
    k: число шагов вычисления значения в узлах
    f: функция правой части ОДУ, реализованная в виде: f(u, x)
    """
 
    def solver_st(self):
        u, f, k, x = self.u, self.f, self.k, self.x
        dx = x[k + 1] - x[k]
        dx2 = dx / 2.0
        K1 = dx * f(u[k], x[k])
        K2 = dx * f(u[k] + 0.5 * K1, x[k] + dx2)
        K3 = dx * f(u[k] + 0.5 * K2, x[k] + dx2)
        K4 = dx * f(u[k] + K3, x[k] + dx)
        u = u[k] + (1 / 6.0) * (K1 + 2 * K2 + 2 * K3 + K4)
 
        u_new = (u[-1] + (dx / 720) * (251 * f(x[-1] + dx) + 646 * f(x[-1], u[-1])
                                       - 264 * f(x[-2], u[-2]) + 106 * f(x[-3], u[-3])
                                       - 19 * f(x[-4], u[-4])))
        # x = (x[-1] + dx)
        return u_new


Насколько корректна такая передача функции правой части ОДУ в методы решателя?

Я заранее очень благодарен, уважаемые форумчане! К сожалению, в разделе научные вычисления активность невысокая, но такая задача не является простым тривиальным примером, и если рассматривать и изучать численные методы, то как правило задачи в иностранной да и нашей литературе более простого характера.

Добавлено через 5 часов 9 минут
Да, воплне возможно, что надо вызвать без импорта из файла import FE, однако все равно в этом случае вызвать требуемый метод не получается, иначе говоря я получаю вполне логично, что выдает исключение raise NotImplementedError, посокльку не реализовано никаких методов, они в другом классе.

Тогда каким образом вызвать мне эти методы?

Добавлено через 1 час 18 минут
Хорошо, проблему с вызовом функции удалось решить, потому что неправильно создавал в тестовом файле сам экземпляр. Вот как надо было в данном случае осуществлять вызов:

Python
1
2
3
4
5
6
7
8
9
# test.py
...
 
y0 = [0, 3, -9, -8, 0]
solver = FE(f)
solver.set_initial_condition(y0)
x_points = np.linspace(0, 5, 150)
u, x = solver.solve(x_points)
plt.plot(x, u)
Однако теперь я получаю ошибку типов:

Code
1
2
3
4
5
6
7
8
Traceback (most recent call last):
  File "C:\Fin_Proj_ODE\test1.py", line 20, in <module>
    u, x = solver.solve(x_points)
  File "C:\Fin_Proj_ODE\ODS.py", line 71, in solve
    self.u[k + 1] = self.solver_st()
  File "C:\Fin_Proj_ODE\ES.py", line 24, in solver_st
    dx = x[k + 1] - x[k]
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Я передаю массив np.linspace () и в самом классе ODE_Solver, прописана процедуры прохода по циклу, и не понимаю, почему в этом случае она не работает, если я передаю на вход массив точек x. В чем может быть проблема?

Добавлено через 1 час 56 минут
Так, понял в чем была ошибка, тогда вопрос следующий, в результате я понял, что мой объект FE не имеет атрибута u, в таком случае я получаю ошибку:

Code
1
2
3
4
5
6
Traceback (most recent call last):
  File "C:\Fin_Proj_ODE\test1.py", line 16, in <module>
    solver = FE(f)
  File "C:\Fin_Proj_ODE\ODS.py", line 21, in __init__
    u, k, x = self.u, self.k, self.x
AttributeError: 'FE' object has no attribute 'u'
В таком случае как организовать правильный вызов метода solve_st из класса FE?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
20.05.2022, 20:25
Ответы с готовыми решениями:

Применение методов правых и левых прямоугольников для решения задач численного интегрирования
Вот такая задача, есть начало и прикрепленный файл с формулой,если есть возможность блок схему... Помогите сегодня кому не сложно, завтра...

Найти максимум численного решения системы ОДУ
Здравствуйте ещё раз. Какие есть функции в Maple для исследования найденного численными методами решения системы дифференциальных...

ОДУ: Несовпадение аналитической асимптотики и численного решения
Здравствуйте. Задача состоит в численном решении уравнения при помощи Matlab и проверке его совпадения с аналитически найденной...

2
8 / 6 / 2
Регистрация: 03.05.2016
Сообщений: 242
21.05.2022, 21:15  [ТС]
В целлом разобрался с ошибкой, и теперь вопрос состоит в следующем. Методы ES и RKS (схема Эйлера и схема Рунге-Кутта 4 порядка работают правильно), однако, остальные схемы не работают, решил объединить схемы Адамса-Башфорта и Адамса-Моултона в одну, поскольку тогджа она является более уточняющей и является модификацией численной схемы Рунге-Кутта. Тогда при вызове возникает следующая проблема. Вызываю данный метод:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import matplotlib.pyplot as plt
import numpy as np
from tabulate import tabulate
from ADS import ABM4
 
 
def exact(x):
    return (np.exp(-3 * x) * (-129 * (x ** 4) - 16 * (x ** 3) + 54 * (x ** 2) + 36 * x)) / 12
 
 
def f(u, x):
    return (u[1],
            u[2],
            u[3],
            u[4],
            - 15 * u[4] - 90 * u[3] -
            270 * u[2] - 405 * u[1] - 243 * u[0])
 
 
y0 = [0, 3, -9, -8, 0]
solver = ABM4(f)
solver.set_initial_condition(y0)
x_points = np.linspace(0, 5, 50)
u, x = solver.solve(x_points)
y = u[:, 0]
plt.plot(x, y, 'bo', linewidth=3, markersize=3)
plt.plot(x, exact(x), 'r-')
plt.grid()
plt.show()
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#ADS.py
 
from abc import ABC
from ODS import ODE_Solver
 
 
class ABM4(ODE_Solver, ABC):
    """
    Реализация классической 4-х шаговой схемы Адамса-Башфорта-Моултона. Явная реализация схемы.
    Возвращает массив решения ОДУ или системы ОДУ.
    Атрибуты класса:
    x: массив узлов точек координаты x
    u: массив решения ОДУ в точках узла x
    k: число шагов вычисления значения в узлах
    f: функция правой части ОДУ, реализованная в виде: f(u, x)
    """
 
    def solver_st(self, alp=None):
        u, f, k, x = self.u, self.f, self.k, self.x
 
        for k in range(0,4):
            dx = x[k + 1] - x[k]
            dx2 = dx / 2.0
            K1 = dx * f(u[k], x[k])
            K2 = dx * f(u[k] + 0.5 * K1, x[k] + dx2)
            K3 = dx * f(u[k] + 0.5 * K2, x[k] + dx2)
            K4 = dx * f(u[k] + K3, x[k] + dx)
            u = u[k] + (1 / 6.0) * (K1 + 2 * K2 + 2 * K3 + K4)
 
        for k in range(4, self.x.size):
            dx = x[k + 1] - x[k]
            alp[k] = dx / 24 * (55 * f(x[k - 1], u[k - 1]) - 59 * f(x[k - 2], u[k - 2]) + 37 * f(x[k - 3], u[k - 3])
                                - 9 * f(x[k - 4], u[k - 4])) + u[k - 1]
            u_new = dx / 24 * (9 * f(x[k], alp[k]) + 19 * f(x[k - 1], u[k - 1]) - 5 * f(x[k - 2], u[k - 2])
                               + f(x[k - 3], u[k - 3])) + u[k - 1]
        return u_new
В результате получаю ошибку следующего характера:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Traceback (most recent call last):
  File "C:\Fin_Proj_ODE\test1.py", line 29, in <module>
    u, x = solver.solve(x_points)
  File "C:\Fin_Proj_ODE\ODS.py", line 71, in solve
    self.u[k + 1] = self.solver_st()
  File "C:\Станкин\CODEMIKA\Fin_Proj_ODE\ADS.py", line 22, in solver_st
    K1 = dx * f(u[k], x[k])
  File "C:\Fin_Proj_ODE\ODS.py", line 20, in <lambda>
    self.f = lambda u, x: np.asarray(f(u, x), float)
  File "C:\Fin_Proj_ODE\test1.py", line 17, in f
    return (u[1],
IndexError: invalid index to scalar variable.
 
Process finished with exit code 1
При том, что если вызвать класс FE из ES.py, то все работает. В чем здесь возникает ошибка и как ее исправить?
0
8 / 6 / 2
Регистрация: 03.05.2016
Сообщений: 242
23.05.2022, 21:34  [ТС]
Удалось решить псоледнюю ошибку и таким образом продолжить работу. В итоге, прише к тому, что надо попробовать написать в итоге уже непосредственно отельный класс, в котором инициализировать непосредственно само ОДУ и вектор для передачи начальных условий Problem
Problem

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np
class Problem(object):
    """Класс описания исходной задачи Коши и минимальный интерфейс запуска методов.
    """
 
    def __init__(self, u0, End):
        self.u0 = np.asarray(u0)
        self.End = End
 
 
    def __call__(self, u, x):
        return (u[1], u[2], u[3], u[4],
                - 15 * u[4] - 90 * u[3] - 270 * u[2] - 405 * u[1] - 243 * u[0])


и написать итоговый класс, в котором можно уже вызывать функцию вывода решения, построения графика, вычисления ошибки, т.е. класс Solver
Solver

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import numpy as np
import matplotlib as plt
import ES
import ODS
from ADS import ABM4
from ES import FE
from MLNS import MLN
from RKS import RK4
 
 
class Solver(object):
    def __init__(self, problem, dx,
                 method=ES.FE):
        """
        """
        self.problem, self.dx = problem, dx
        self.solver = method
 
    @staticmethod
    def choose_sch(type):
        if type == 1:
            method = FE
            return method
        elif type == 2:
            method = RK4
            return method
        elif type == 3:
            method = ABM4
            return method
        elif type == 4:
            method = MLN
            return method
        else:
            raise ValueError('Необходимо выбрать численную схему решателя!')
 
    def dsolve(self):
        solver = self.method(self.problem)
        solver.set_initial_condition(self.problem.u0)
        n = int(round(self.problem.End / self.dx))
        x_points = np.linspace(0, self.problem.End, n + 1)
        self.u, self.x = solver.solve(x_points)
 
        if solver.k + 1 == n:
            self.plot()
            raise ValueError('не обеспечена сходимость численного метода,' % self.problem.End)
 
    def plot(self):
        plt.plot(self.x, self.u)
        plt.show()


Таким образом, вызов решателя и функций класса Solver будут иметь вид:
Solver

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
from ODE_Problem import Problem
from SLV_Prob import Solver
 
 
def test():
    problem = Problem(u0=[0, 3, -9, -8, 0], End=5)
    solver = Solver(problem, dx=0.1)
    solver.dsolve()
    solver.plot()
 
 
if __name__ == '__main__':
    test()


Непосредственно код самой схемы решателя ODE_Solver такой же:
ODE_Solver

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import numpy as np
 
 
class ODE_Solver(object):
    """
    Суперкласс для решения ОДУ или системы ОДУ нормированной и приведенной к виду: du/dx = f(u, x)
    Атрибуты класса:
    x: массив узлов точек координаты x
    u: массив решения ОДУ в точках узла x
    k: число шагов вычисления значения в узлах
    f: функция правой части ОДУ, реализованная в виде: f(u, x)
    err_sch: оценка погрешности дискретизации метода E = O(h)
    Погрешность вычислений явлется суммой погрешности дискретизации
    и погрешностей округления.
    """
 
    def __init__(self, f):
        if not callable(f):
            # проверка корректности типа передаваемой функции f(u, x)
            raise TypeError('f не %s, является функцией' % type(f))
        # инициализация функции правой части ОДУ
        self.f = lambda u, x: np.asarray(f(u, x), float)
        self.err_sch = None
 
    def solver_st(self):
        """
        Реализация конктреной численной схемы решателя.
        Вычисление значения функции решения ОДУ на одном шаге
        Функция возвращает значение решения на шаге k.
        """
 
        raise NotImplementedError
 
    def err_st(self):
        """Расчет погрешности дискретизаци схемы. Зависит от выбранного метода и шага."""
 
        raise NotImplementedError
 
    def set_initial_condition(self, u0):
        """
        Решение ОДУ и  запись полученных значений в виде массива или списка.
        По умолчанию функция возвращает False, если нет элементов.
        """
 
        if isinstance(u0, (float, int)):  # ОДУ является одномерным
            self.neq = 1
            u0 = float(u0)
        else:  # система ОДУ, ОДУ порядка выше 1-го
            u0 = np.asarray(u0)  # (начальные условия вектор-функция - порядок 2+)
            self.neq = u0.size
        self.u0 = u0
 
        # Проверка, что функция возвращает вектор f корректной длины:
        try:
            f0 = self.f(self.u0, 0)
        except IndexError:
            raise IndexError(
                'Индекс вектора u выходит за границы f(u,x). Допустимые индексы %s' % (str(range(self.neq))))
        if f0.size != self.neq:
            raise ValueError('f(u,x) возвращено %d элементов, вектор u имеет %d элементов' % (f0.size, self.neq))
 
    def solve(self, coord_points, terminate=None):
        """
        Решение ОДУ и  запись полученных значений в виде массива или списка.
        По умолчанию функция возвращает False, если нет элементов.
        """
 
        # используется для контроля шага - в случае реализации адаптивных методов позволяет
        # вести контроль за выборо шага на сетке узлов решения. Не используется для методов:
        # FE, RK4, ABM4, MLN.
        if terminate is None:
            terminate = lambda u, x, step_no: False
 
        if isinstance(coord_points, (float, int)):
            raise TypeError('solve: массив точек x не содержит чисел.')
        self.x = np.asarray(coord_points)
        if self.x.size <= 1:
            raise ValueError('ODESolver.solve требует на вход массив координат'
                             ' точек поиска решения. Число точек меньше 2!')
 
        n = self.x.size
        if self.neq == 1:  # ОДУ
            self.u = np.zeros(n)
            self.err_sch = np.zeros(n)
        else:  # ОДУ порядка 2+ или система ОДУ
            self.u = np.zeros((n, self.neq))
            self.err_sch = np.zeros((n, self.neq))
 
        # Присвоить self.x[0] значение начального условия  self.u0
        self.u[0] = self.u0
        self.err_sch[0] = 0
 
        # Проход по сетке координат узлов, в которых отыскивается решение.
        # Используется векторизация посрдеством хранения данных в  numpy array.
        for k in range(n - 1):
            self.k = k
            self.u[k + 1] = self.solver_st()
            self.err_sch[k + 1] = self.err_st()
            if terminate(self.u, self.x, self.k + 1):
                break
        return self.u[:k + 2], self.x[:k + 2]


При запуске я получаю следующего рода ошибку:
Code
1
2
3
4
5
6
7
 File "C:\Fin_Proj_ODE\test2.py", line 14, in <module>
    test()
  File "C:\Fin_Proj_ODE\test2.py", line 9, in test
    solver.dsolve()
  File "C:\\Fin_Proj_ODE\SLV_Prob.py", line 37, in dsolve
    solver = self.method(self.problem)
AttributeError: 'Solver' object has no attribute 'method'
Каким образом ее можно решить?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
23.05.2022, 21:34
Помогаю со студенческими работами здесь

Решения задач Коши для ОДУ 1 порядка
Найти решения двух задач Коши для ОДУ 1 порядка на отрезке с точностью 0.0001 методом Рунге-Кутты 3-го порядка. Построить графики...

Метод Эйлера для решения ОДУ первого порядка
Здравствуйте! Вроде бы реализовала программу для решения диффура 1-го порядка методом Эйлера (функция y=xcos(x), пределы...

Разработать подпрограмму для решения ОДУ методом Рунге-Кутта 4-го порядка
разработать подпрограмму для решения ОДУ методом &quot;Рунге-Кутта&quot; &quot;4-го&quot; порядка

Составить процедуру численного решения задачи Коши для дифференциального уравнения 1-го порядка методом Милна
Составить процедуру численного решения задачи Коши для дифференциального уравнения 1-го порядка методом Милна.

Один из методов численного решения нелинейного уравнения
Функция y = f(x) задана неявно уравнением F(x,y) = 0. На отрезке построить таблицу значений функции y=f(x) с шагом h=0.5, применяя один из...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru