commit 5c01c4d176e8ac5c91d2afacdad71acbdc74b94e Author: svxf Date: Fri Mar 15 13:50:21 2019 +0400 git reimport diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..b9ba84f --- /dev/null +++ b/Pipfile @@ -0,0 +1,11 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +[requires] +python_version = "3.7" diff --git a/float_roots.pickle b/float_roots.pickle new file mode 100644 index 0000000..d021552 Binary files /dev/null and b/float_roots.pickle differ diff --git a/saved_roots_1000.pickle b/saved_roots_1000.pickle new file mode 100644 index 0000000..6d950c4 Binary files /dev/null and b/saved_roots_1000.pickle differ diff --git a/src/__pycache__/solver.cpython-37.pyc b/src/__pycache__/solver.cpython-37.pyc new file mode 100644 index 0000000..15bef4d Binary files /dev/null and b/src/__pycache__/solver.cpython-37.pyc differ diff --git a/src/app.py b/src/app.py new file mode 100644 index 0000000..a073d5e --- /dev/null +++ b/src/app.py @@ -0,0 +1,171 @@ +import sys + +from PyQt5.QtWidgets import QApplication, QGridLayout, QGroupBox, QLabel, QLineEdit, QMessageBox, QPushButton, \ + QSizePolicy, QVBoxLayout, QWidget +from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas +from matplotlib.figure import Figure + +import solver + + +class App(QWidget): + + def __init__(self): + super().__init__() + + self.solver = solver.Solver() + + self.grid = QGridLayout() + self.setLayout(self.grid) + + self.resize(1200, 600) + + self.plot = PlotCanvas(width=10, height=4) + self.grid.addWidget(self.plot, 1, 1, 1, 1) + + param_box = QGroupBox() + + param_vbox = QVBoxLayout() + + param_vbox.addWidget(QLabel('Длина цилиндра l')) + self.l_field = QLineEdit('20') + self.l_field.setStyleSheet("color: black;") + param_vbox.addWidget(self.l_field) + + param_vbox.addWidget(QLabel('Коэффициент диффузии D')) + self.D_field = QLineEdit('0.6') + self.D_field.setStyleSheet("color: black;") + param_vbox.addWidget(self.D_field) + + param_vbox.addWidget(QLabel('Мембранный коэффициент диффузии H')) + self.H_field = QLineEdit('4') + self.H_field.setStyleSheet("color: black;") + param_vbox.addWidget(self.H_field) + + param_vbox.addWidget(QLabel('Момент времени t')) + self.t_field = QLineEdit('0') + self.t_field.setStyleSheet("color: black;") + param_vbox.addWidget(self.t_field) + + param_vbox.addWidget(QLabel('Точность поиска собственных значений')) + self.eps_field = QLineEdit('1e-9') + self.eps_field.setStyleSheet("color: black;") + param_vbox.addWidget(self.eps_field) + + param_vbox.addWidget(QLabel('Количество членов ряда в суммировании')) + self.sum_count_field = QLineEdit('100') + self.sum_count_field.setStyleSheet("color: black;") + param_vbox.addWidget(self.sum_count_field) + + calc_button = QPushButton('Рассчитать') + calc_button.pressed.connect(self.calc) + param_vbox.addWidget(calc_button) + + param_vbox.addStretch(1) + param_box.setLayout(param_vbox) + + self.grid.addWidget(param_box, 1, 2, 1, 1) + + self.calc() + + def show_error(self, text): + msg = QMessageBox() + msg.setIcon(QMessageBox.Information) + + msg.setText(text) + msg.setWindowTitle("Ошибка расчетов") + msg.setStandardButtons(QMessageBox.Ok) + + msg.exec_() + + def calc(self): + try: + l_str = self.l_field.text() + l_val = float(l_str) + except Exception as e: + self.show_error(f'Некорректный формат числа: {l_str}') + return + + try: + D_str = self.D_field.text() + D_val = float(D_str) + except Exception as e: + self.show_error(f'Некорректный формат числа: {D_str}') + return + + try: + H_str = self.H_field.text() + H_val = float(H_str) + except Exception as e: + self.show_error(f'Некорректный формат числа: {H_str}') + return + + try: + t_str = self.t_field.text() + t_val = float(t_str) + except Exception as e: + self.show_error(f'Некорректный формат числа: {t_str}') + return + + try: + eps_str = self.eps_field.text() + eps_val = float(eps_str) + except Exception as e: + self.show_error(f'Некорректный формат числа: {eps_str}') + return + + try: + sum_count_str = self.sum_count_field.text() + sum_count_val = int(sum_count_str) + except Exception as e: + self.show_error(f'Некорректный формат числа: {sum_count_str}') + return + + if not ( + 1e-3 <= l_val <= 1e+3 and + 1e-3 <= D_val <= 1e+3 and + 1e-3 <= H_val <= 1e+3 and + 0 <= t_val <= 1e+3 and + 1e-20 <= eps_val <= 1e+3 and + 1 <= sum_count_val <= 1e+3 + ): + self.show_error(f'Некорректные входные данные') + return + + self.solver.set_params(l_val, D_val, H_val, t_val, eps_val, sum_count_val) + + plot_x, plot_y = self.solver.calc() + + self.plot.plot(plot_x, plot_y) + + +class PlotCanvas(FigureCanvas): + def __init__(self, parent=None, width=4, height=4, dpi=100): + fig = Figure(figsize=(width, height), dpi=dpi) + self.axes = fig.add_subplot(111) + + FigureCanvas.__init__(self, fig) + self.setParent(parent) + + FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding) + FigureCanvas.updateGeometry(self) + + def plot(self, plot_x, plot_y): + self.axes.clear() + + self.axes.plot(plot_x, plot_y) + self.axes.set_xlabel('$x, \\mathrm{м}$') + self.axes.set_ylabel('$u$') + self.axes.set_title('Поле концентрации вещества в цилиндре, $\\frac{\\mathrm{кг}}{\\mathrm{м}^3}$') + + self.axes.set_ylim(0, None) + + self.axes.grid(True) + self.draw() + + +if __name__ == '__main__': + app = QApplication(sys.argv) + ex = App() + ex.show() + sys.exit(app.exec_()) diff --git a/src/solver.py b/src/solver.py new file mode 100644 index 0000000..457fa31 --- /dev/null +++ b/src/solver.py @@ -0,0 +1,114 @@ +import datetime +import pickle + +import numpy as np + + +class Solver: + def __init__(self): + self.l = None + self.D = None + self.H = None + self.t = None + + self.eps = 1e-9 + self.sum_count = 100 + + self.alphas = np.zeros(0) + + def find_root(self, index): + C = self.H * self.l / 2 + + l = np.pi * index + self.eps + r = np.pi * index + np.pi / 2 - self.eps + + while True: + m = (l + r) / 2 + val = np.tan(m) - C / m + + if abs(val) < self.eps or abs(r - l) < self.eps: + return m + + if val > 0: + r = m + else: + l = m + + def set_params(self, l, D, H, t, eps, sum_count): + self.l = l + self.D = D + self.H = H + self.t = t + self.eps = eps + self.sum_count = sum_count + + self.alphas = np.array([self.find_root(i) for i in range(self.sum_count)]) + + def calc(self): + plot_x = np.linspace(0, self.l, 1000) + + start_dt = datetime.datetime.utcnow() + + plot_y = np.array([self.calc_single(x) for x in plot_x]) + + end_dt = datetime.datetime.utcnow() + + print((end_dt - start_dt) / 1000) + + return plot_x, plot_y + + # noinspection PyTypeChecker + def calc_single(self, x: float) -> float: + if self.l is None: + raise ValueError('Not initialized') + + # @formatter:off + return np.sum( + ( + -4 * np.pi ** 2 * ( + self.H * self.l * np.sin(2 * self.alphas * x / self.l) + + 2 * self.alphas * np.cos(2 * self.alphas * x / self.l) + ) * ( + -self.H * self.l * np.cos(2 * self.alphas) + + self.H * self.l + + 2 * self.alphas * np.sin(2 * self.alphas) + ) * np.exp( + -4 * self.D * self.alphas ** 2 * self.t / self.l ** 2 + ) / ( + 5 * ( + self.alphas ** 2 + - np.pi ** 2 + ) * ( + 4 * self.H ** 2 * self.alphas * self.l ** 2 + - self.H ** 2 * self.l ** 2 * np.sin(4 * self.alphas) + - 4 * self.H * self.alphas * self.l * (np.cos(4 * self.alphas) - 1) + + 4 * self.alphas ** 2 * ( + 4 * self.alphas + + np.sin(4 * self.alphas) + ) + ) + ) + ) + ) + # @formatter:on + + +with open('float_roots.pickle', 'rb') as file: + float_roots = pickle.load(file) + + +def u_elem(x, t, alpha_n): + return -4 * np.pi ** 2 * (alpha_n * np.cos(alpha_n * x / 10) + 40 * np.sin(alpha_n * x / 10)) * ( + alpha_n * np.sin(2 * alpha_n) - 40 * np.cos(2 * alpha_n) + 40) * np.exp(-3 * alpha_n ** 2 * t / 500) / ( + 5 * (alpha_n ** 2 - np.pi ** 2) * (alpha_n ** 2 * (4 * alpha_n + np.sin(4 * alpha_n)) - 80 * alpha_n * ( + np.cos(4 * alpha_n) - 1) + 6400 * alpha_n - 1600 * np.sin(4 * alpha_n))) + + +def u(x, t): + return np.sum(u_elem(x, t, float_roots)) + + +if __name__ == '__main__': + solver = Solver() + solver.set_params(20, 0.6, 4, 10) + print(solver.calc(10))