I try to implement ODE Solver contain deifferent numerical schemes for solve ODE 5-th order:
For example consider the Forward Euler scheme code implementation:
# ES.py
from abc import ABC
from ODS import ODE_Solver
class FE(ODE_Solver, ABC):
"""
Attribute:
x: array of x coords
u: solution array y(x)
k: number of steps
f: right hand side ODE equation: du/dx = f(u, x)
"""
@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
This method code by class and contain one method and based on superclass ODE_Solver:
#ODS.py
import numpy as np
class ODE_Solver(object):
"""
Supercalss sover ODE-s
Attribute:
x: array of x coords
u: solution array y(x)
k: number of steps
f: right hand side ODE equation: du/dx = f(u, x)
"""
def __init__(self, f):
if not callable(f):
# check correct function f(u, x)
raise TypeError('f is %s, not function' % type(f))
self.f = lambda u, x: np.asarray(f(u, x), float)
def solver_st(self):
"""Implement numerical scheme"""
raise NotImplementedError
def set_initial_condition(self, u0):
if isinstance(u0, (float, int)): # ODE 1-th order
self.neq = 1
u0 = float(u0)
else: # ODE high order or system of ODE-s
u0 = np.asarray(u0) # (initial conds)
self.neq = u0.size
self.u0 = u0
# check correct lenght of vector f
try:
f0 = self.f(self.u0, 0)
except IndexError:
raise IndexError(
'index out of bounds f(u,x). right index %s' % (str(range(self.neq))))
if f0.size != self.neq:
raise ValueError('f(u,x) return %d elems, u has %d elems' % (f0.size, self.neq))
def solve(self, coord_points, terminate=None):
"""
Solve equations. Default False
"""
if terminate is None:
terminate = lambda u, x, step_no: False
if isinstance(coord_points, (float, int)):
raise TypeError('solve: array lists not iterable')
self.x = np.asarray(coord_points)
if self.x.size <= 1:
raise ValueError('ODESolver.solve requre coords x array')
n = self.x.size
if self.neq == 1: # ODE
self.u = np.zeros(n)
else:
self.u = np.zeros((n, self.neq))
# Assume self.x[0] corresponds to self.u0
self.u[0] = self.u0
# looping for x coords
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
return self.u[:k + 2], self.x[:k + 2]
And now I try to testing my code:
# test.py
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 = FE(f)
solver.set_initial_condition(y0)
x_points = np.linspace(0, 5, 150)
u, x = solver.solve(x_points)
plt.plot(x, u)
So I consider the reccomendation in commentary I succes to call solver methods, but I get type error:
File "C:\Fin_Proj_ODE\test1.py", line 19, 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 18, in solver_st
u, f, k, x = self.u, self.f, self.k, self.x
AttributeError: type object 'FE' has no attribute 'u'
This post not help me to decide this troubleshooting
And I have 2 questions:
1) How to fix this error of call methods of required class? Any idea?
- How to rewrite class for calling methods in test file from EF class?
ImportError: cannot import name 'ODE_Solver' - this bug related with wrong call methods of class EF:
solver = ODE_Solver.solver_st(f)
solver.set_initial_condition(y0)
x_points = np.linspace(0, 5, 150)
u, x = solver.solve(x_points)