Nikita Smirnov, IU BS18-04 student
November 2019
github.com/pakrentos/deproject
Let us proceed with the analytical solution of FO ODE first
Turning ODE into separable equation:
Simple matplotlib-based plotter for solving IVP for concrete equation. I decided to use python and such libraries as PyQt5 and matplotlib due to their functionality and using ease.
Program consists of 3 parts: graphs OOP implementation, plotting widget, and main window.
-
The most difficult part was implementing pure OOP in Python due to the lack of native support for abstract classes and encapsulation. The hierarchy of self-written graph classes is simple. The main class is the Graph class; it is also abstract. His heirs are analytical and approximating (Euler's method, Euler's improved method and Runge-Kutta method) graphs. Two helper classes are used to calculate local and total errors.
-
The matplotlib part is a widget built into the PyQt window. Its main graphic part is processed using the PyQt library, the rest is implemented as an abstract canvas and its parameters
-
PyQt part consists only of widgets interconnected using a simplified MVC model, namely, signals and slots
import ABC, abstractmethod
class Graph(ABC):
def __init__(self, name, x0=1, y0=0.5, X=9, n=10):
self.__x0 = x0
self.__X = X
self.__n = n
self.__y0 = y0
self.__name = name
self.__xgrid = []
self.__ygrid = []
self.__grid_step = (X - x0)/n
while x0 < X:
self.__xgrid.append(x0)
x0 += self.__grid_step
self.__calc()
super().__init__()
@abstractmethod
def __calc(self):
pass
def recalculate(self, x0, y0, X, n):
self.__x0 = x0
self.__X = X
self.__n = n
self.__y0 = y0
self.__xgrid.clear()
self.__ygrid.clear()
self.__grid_step = (X - x0)/n
while x0 < X:
self.__xgrid.append(x0)
x0 += self.__grid_step
self.__calc()
def get_grid(self):
return self.__xgrid, self.__ygrid, self.__name
class ExactGraph(Graph):
def __func(self, x, c):
try:
res = 1/(c*x+1)
except (OverflowError, ZeroDivisionError) as e:
res = np.nan
threshold = 50
res = np.ma.masked_less(res, -1*threshold)
res = np.ma.masked_greater(res, threshold)
return res
def _Graph__calc(self):
c = 1/self._Graph__y0 - 1
for x_i in self._Graph__xgrid:
self._Graph__ygrid.append(self.__func(x_i, c))
class ErrorGraph:
def __init__(self, exact_graph, approx_graph, name):
self.__exact = exact_graph
self.__approx = approx_graph
self.__name = name
self.__ygrid = [
x1 - x2 for (x1, x2) in zip(self.__exact.get_grid()[1],
self.__approx.get_grid()[1])]
self.__xgrid = self.__exact.get_grid()[0]
def recalculate(self, *args):
self.__ygrid = [x1 - x2 for (x1, x2) in zip(self.__exact.get_grid()[1], self.__approx.get_grid()[1])]
self.__xgrid = self.__exact.get_grid()[0]
def get_grid(self):
return self.__xgrid, self.__ygrid, self.__name
class PlotCanvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot()
FigureCanvas.__init__(self, fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,
QSizePolicy.Expanding,
QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
self.ax = self.figure.add_subplot(111)
self.ax.set_xlabel('X axis')
self.ax.set_ylabel('Y axis')
self.ax.set_title('y\'=(y^2 - y)/x')
def clr(self):
self.ax.clear()
self.ax.set_xlabel('X axis')
self.ax.set_ylabel('Y axis')
self.ax.set_title('y\'=(y^2 - y)/x')
self.draw()
def plot(self, xgrid, ygrid, label, color):
self.ax.plot(xgrid, ygrid, color, label=label)
self.ax.legend(fontsize='small')
self.draw()
As we can see from the graphs (provided in the end of the PDF-file) Runge- Kutta is indeed the most presice method among those 3. As we can see from the graph of local error, Euler method is indeed the least precise method. Runge- Kutta is the most precise method of all of them. We can also note from the total error graphs that Euler method total error is
The code is written on Python language that supports OOP. It does not contradict the solid OOP principles:
The code is easy to extend without modifying it. For example, to implement the other solution method it is only necessary to extend from graph and implement 2-3 features.
Objects in my project can be substituted with their subtypes
PyQt and matplotlib does not contradict Interface segregation principle.
This code does not depend on details
![image-20191115140438504](/Users/nikitasmirnov/Library/Application Support/typora-user-images/image-20191115140438504.png)
![image-20191115140503918](/Users/nikitasmirnov/Library/Application Support/typora-user-images/image-20191115140503918.png)
![image-20191115140522291](/Users/nikitasmirnov/Library/Application Support/typora-user-images/image-20191115140522291.png)
![image-20191115140537020](/Users/nikitasmirnov/Library/Application Support/typora-user-images/image-20191115140537020.png)
![image-20191116114523544](/Users/nikitasmirnov/Library/Application Support/typora-user-images/image-20191116114523544.png)
![image-20191116114538912](/Users/nikitasmirnov/Library/Application Support/typora-user-images/image-20191116114538912.png)
![image-20191116114554710](/Users/nikitasmirnov/Library/Application Support/typora-user-images/image-20191116114554710.png)