AttributeError: 'Solver' object has no attribute 'method' at implementig class solver ODE

AttributeError: 'Solver' object has no attribute 'method' at implementig class solver ODE

现在,除了我之前的两篇文章 ODE implements,我尝试重构我的代码并修复一些问题。我决定,从逻辑上创建这样的 classes:Solver,Problem.

所以 ODE_Solver 和 FE class 的代码终于可以正常工作了。

# ODS.py

import numpy as np


class ODE_Solver(object):
 

    def __init__(self, f):
        if not callable(f):

            raise TypeError('f is not %s, function' % type(f))

        self.f = lambda u, x: np.asarray(f(u, x), float)
        self.err_sch = None

    def solver_st(self):


        raise NotImplementedError

    def err_st(self):

        raise NotImplementedError

    def set_initial_condition(self, u0):


        if isinstance(u0, (float, int)):  
            self.neq = 1
            u0 = float(u0)
        else:  
            u0 = np.asarray(u0) 
            self.neq = u0.size
        self.u0 = u0

        try:
            f0 = self.f(self.u0, 0)
        except IndexError:
            raise IndexError(
                'index out of bounds f(u,x). correct index %s' % (str(range(self.neq))))
        if f0.size != self.neq:
            raise ValueError('f(u,x) returend %d elems, vector u has %d elems' % (f0.size, self.neq))

    def solve(self, coord_points, terminate=None):

        if terminate is None:
            terminate = lambda u, x, step_no: False

        if isinstance(coord_points, (float, int)):
            raise TypeError('solve: x points not numpy array or numbers.')
        self.x = np.asarray(coord_points)
        if self.x.size <= 1:
            raise ValueError('ODESolver.solve points of coords less than two')

        n = self.x.size
        if self.neq == 1:  # ОДУ
            self.u = np.zeros(n)
            self.err_sch = np.zeros(n)
        else:  
            self.u = np.zeros((n, self.neq))
            self.err_sch = np.zeros((n, self.neq))

        self.u[0] = self.u0
        self.err_sch[0] = 0

        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]
# ES.py
from ODS import ODE_Solver
import numpy as np


class FE(ODE_Solver):

    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 err_st(self):
        u, f, k, x, err_sch = self.u, self.f, self.k, self.x, self.err_sch
        dx = x[k + 1] - x[k]
        err_sch = np.max(dx)**2
        return err_sch

我尝试实现 class Problem(return ODE 并获取初始条件)

import numpy as np

class Problem(object):

    def __init__(self, u0, End):

        self.u0 = np.asarray(u0)
        self.End = End # end point of coords


    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])

和代码class Solver调用数值方案,绘制最终结果,绘制和评估错误:

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): # choose FE scheme for tetsting
        """
        """
        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('not choose numerical scheme!')

    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('not converge this scheme,' % self.problem.End)

    def plot(self):
        plt.plot(self.x, self.u)
        plt.show()

现在,当我调用这个 SolverProblem

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()

我得到错误:

Traceback (most recent call last):
  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'

而且我不明白并猜想这个错误的原因...

所以,我有 2 个关于实现这个求解器的问题

  1. 如何修复这个错误?
  2. 如何更正重写 def choose_sch(type):,我可以调用求解器并发送 args 类型(并且取决于它,一个特定的数字方案已经开始) ?

问题一:

好吧,正如错误所述,您的规划求解 class 没有名为“方法”的属性。你的属性实际上是“求解器”,所以不是调用

self.method(self.problem)

尝试

self.solver(self.problem)

问题二:

如果我的理解正确,您想知道如何从求解器构造函数中调用 choose_sch 方法并直接采用类型而不是方法。为此,只需执行以下操作:

class Solver(object):
    def __init__(self, problem, dx, solver_type=1): # choose FE scheme for tetsting
        """
        """
        self.problem, self.dx = problem, dx
        self.solver = self._choose_sch(solver_type)

    @staticmethod
    def _choose_sch(solver_type):
        methods = {1: FE, 2: RK4, 3: ABM4, 4: MLN}
        if solver_type in methods:
            return methods[solver_type]
        else:
            raise ValueError('not choose numerical scheme!')

对于这类任务,这里的字典比 if 语句要好得多。

如果您不需要从静态上下文中调用它,您也可以不将 _choose_ach 设为静态方法,而只需让它直接设置求解器。