Advertisement
Guest User

for Lexa

a guest
Apr 17th, 2018
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.02 KB | None | 0 0
  1. # necessary in order to compile this script to .exe
  2. from matplotlib import use as matplotlib_use
  3. matplotlib_use("QT5Agg")
  4.  
  5. import os
  6. import sys
  7. import numpy
  8. import decimal
  9. from numpy import log10, sqrt, power, exp, log
  10. from decimal import Decimal
  11.  
  12. from PyQt5.QtWidgets import *
  13. from PyQt5.QtGui import QFont
  14. from PyQt5 import QtCore
  15.  
  16. from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
  17. from matplotlib import pyplot as plt
  18. from matplotlib.figure import Figure
  19.  
  20. decimal.getcontext().prec = 100
  21.  
  22. class InputField:
  23.     def __init__(self, text, coeffSI, left_bound = None, right_bound = None):
  24.         self.text = text
  25.         self.coeffSI = Decimal(coeffSI)
  26.         self.left_bound = left_bound
  27.         self.right_bound = right_bound
  28.  
  29. inputFields = {
  30.     'Epsilon' : InputField('Шероховатость трубопровода, мм', 1e-3, 0.001, 10),
  31.     'Q' : InputField('Объемная скорость потока, м^3 / c', 1.0, 0.001, 1000),
  32.     'd' : InputField('Диаметр трубопровода, мм', 1e-3, 1, 2000),
  33.     'v_n' : InputField('Вязкость нефти, сСт', 1e-6),
  34.  
  35.     'v_p' : InputField('Вязкость присадки, сСт', 1e-6),
  36.     'V_por' : InputField('Пороговая скорость, м / с', 1.0, 0.0001, 0.3),
  37.  
  38.     'c_left_bound' : InputField('Начальная концентрация, ppm', 1e-6, 0, 350),
  39.     'c_right_bound' : InputField('Конечная концентрация, ppm', 1e-6, 0, 350),
  40.     'c_points_count' : InputField('Количество точек построения', 1.0, 3, 1000),
  41.     'k_left' : InputField('начальный коэффициент концентрации присадки', 1.0),
  42.     'k_right' : InputField('конечный коэффициент концентрации присадки', 1.0),
  43.  
  44.     'concentration_coefficient' : InputField('Коэффициент Z', 1.0, 1, 2e5),
  45. }
  46.  
  47. class Equation:
  48.  
  49.     def __init__(self):
  50.         self.Epsilon = 0
  51.         self.Q = 0
  52.         self.d = 0
  53.         self.v_n = 0
  54.         self.k = 0
  55.  
  56.         self.v_p = 0
  57.         self.V_por = 0
  58.  
  59.         self.c_left_bound = 0
  60.         self.c_right_bound = 0
  61.         self.c_points_count = 0
  62.         self.k_left = 0
  63.         self.k_right = 0
  64.  
  65.         self.lambda_left_bound = Decimal(1e-20)
  66.         self.lambda_right_bound = Decimal(1)
  67.         self.lambda_bruteforce_step = Decimal(1e-4)
  68.  
  69.         self.bin_search_max_operations = 100
  70.         self.bin_search_precision = Decimal(1e-8)
  71.  
  72.     def outOfBounds(self, value, field):
  73.         conditionLeft = conditionRight = False
  74.         if (field.left_bound):
  75.             left_bound = Decimal(field.left_bound)
  76.             conditionLeft = value < left_bound and abs(value - left_bound) > 1e-10
  77.  
  78.         if (field.right_bound):
  79.             right_bound = Decimal(field.right_bound)
  80.             conditionRight = value > right_bound and abs(value - right_bound) > 1e-10
  81.  
  82.         return conditionLeft or conditionRight
  83.  
  84.     def setData(self, name, textValue):
  85.         try:
  86.             field = inputFields[name]
  87.             assert(field)
  88.             value = Decimal(textValue.replace(',', '.'))
  89.             if self.outOfBounds(value, field):
  90.                 raise ValueError()
  91.             setattr(self, name, value * field.coeffSI)
  92.  
  93.         except AssertionError:
  94.             raise Exception('Wrong field "{0}" in function Equation.setData() \n Сообщите программистам об ошибке'.format(name))
  95.         except decimal.InvalidOperation:
  96.             raise Exception('Некорректные данные в поле "{0}" \n' \
  97.                 'Допускаются цифры и точка либо запятая в качестве разделителя'.format(field.text))
  98.         except ValueError:
  99.             raise Exception('Значение в поле "{0}" должно лежать в пределах от {1} до {2}'.format(field.text, field.left_bound, field.right_bound))
  100.  
  101.     def left_log(self, x):
  102.         if self.concentration_coefficient < Decimal(1e-10):
  103.             return Decimal(1)
  104.         x = Decimal(x)
  105.         base = (Decimal(2.8) * self.V_por) / (self.V * Decimal(sqrt(x)))
  106.         p = self.beta / Decimal(5.75)
  107.         return Decimal(power(base, p))
  108.  
  109.     def right_log(self, x):
  110.         return Decimal(2.51) / (self.Re * Decimal(sqrt(x))) + self.Epsilon / (Decimal(3.7) * self.d)
  111.  
  112.     def right_side(self, x):
  113.         #return Decimal(-2.0) * Decimal(log10(self.left_log(x) * self.right_log(x)))
  114.         return Decimal(0.88) * Decimal(log10(Decimal(self.k) * self.Re * Decimal(sqrt(x)))) - Decimal(3.745)
  115.  
  116.     def left_side(self, x):
  117.         return Decimal(1) / Decimal(sqrt(x))
  118.  
  119.     def brute_force_lambda(self):
  120.         min_diff = 1e10
  121.         min_lambda = -1;
  122.         for i in numpy.arange(self.lambda_left_bound, self.lambda_right_bound, self.lambda_bruteforce_step):
  123.             cur_diff = abs(self.left_side(i) - self.right_side(i))
  124.             if (min_diff > cur_diff):
  125.                 min_diff = cur_diff
  126.                 min_lambda = i
  127.         return min_lambda
  128.  
  129.     def bin_search_lambda(self):
  130.         L, R = self.lambda_left_bound, self.lambda_right_bound
  131.         coeffL = self.left_side(L) - self.right_side(L)
  132.         coeffR = self.left_side(R) - self.right_side(R)
  133.  
  134.         coeffL /= abs(coeffL)
  135.         coeffR /= abs(coeffR)
  136.         iterations = 0
  137.  
  138.         if coeffL * coeffR > 0:
  139.             return self.brute_force_lambda()
  140.  
  141.         while iterations < self.bin_search_max_operations and abs(L - R) > self.bin_search_precision:
  142.             iterations += 1
  143.             mid = (L + R) / Decimal(2.0);
  144.  
  145.             if coeffL * (self.left_side(mid) - self.right_side(mid)) > 0.0:
  146.                 L = mid
  147.             else:
  148.                 R = mid
  149.  
  150.         return L
  151.  
  152.     def showPlot(self, progressBar):
  153.         CC_array = []
  154.         lambda_array = []
  155.         DR_array = []
  156.  
  157.         c_step = (self.c_right_bound - self.c_left_bound) / (self.c_points_count - 1)
  158.         self.V = Decimal(4.0) * self.Q / (Decimal(numpy.pi) * self.d * self.d)
  159.         self.Re = self.V * self.d / self.v_n
  160.         self.beta = 0
  161.  
  162.         # k_left, k_right = self.k_left, self.k_right
  163.         self.k = self.k_left
  164.         lambda_0 = self.bin_search_lambda()
  165.         progressBar.setRange(self.k, self.k_right)
  166.  
  167.         while(self.k <= self.k_right):
  168.             if progressBar.wasCanceled():
  169.                 return
  170.             progressBar.setValue(int(self.k))
  171.  
  172.             c_p = self.c_left_bound #c_step * Decimal(iteration)
  173.             c_n = Decimal(1) - c_p
  174.  
  175.             # пересчет вязкости раствора при по формуле Вальтера
  176.             K = Decimal(0.8)
  177.             sum = c_n * log10(log10(K + self.v_n / inputFields['v_n'].coeffSI)) + c_p * log10(log10(K + self.v_p / inputFields['v_p'].coeffSI))
  178.             v_r = power(Decimal(10), power(Decimal(10), sum)) - K
  179.             v_r = v_r * inputFields['v_n'].coeffSI
  180.  
  181.             # if (c_p > 1e-8):
  182.             #     nu = (v_r - self.v_n) / (self.v_n * c_p)
  183.             #     tay = Decimal(8.31 * 293) / Decimal(1e6) / nu
  184.             #     print(sqrt(tay / Decimal(1000)))
  185.  
  186.             # число Рейнольдса
  187.             self.Re = self.V * self.d / v_r
  188.             self.beta = self.concentration_coefficient * c_p * Decimal(100) # умножаем на 100, т.к. в формуле СС в процентах
  189.  
  190.             CC_array.append(self.k)
  191.             lambda_array.append(self.bin_search_lambda())
  192.             DR_array.append(100 * (1 - lambda_array[-1] / lambda_0))
  193.             self.k = self.k + 1
  194.             # print('{} {}'.format(CC_array[-1], lambda_array[-1]))
  195.  
  196.         fig, ax1 = plt.subplots()
  197.         ax1.plot(CC_array, lambda_array, 'b')
  198.         ax1.set_xlabel('Коэффициент k(в новой формуле)')
  199.         ax1.set_ylabel('Коэффициент трения', color='b')
  200.         ax1.tick_params('y', colors='b')
  201.  
  202.         ax1.grid(True)
  203.  
  204.         # ax2 = ax1.twinx()
  205.         # ax2.plot(CC_array, DR_array, 'r')
  206.         # ax2.set_ylabel('Гидравлическая эффективность присадки, %', color='r')
  207.         # ax2.tick_params('y', colors='r')
  208.  
  209.         # ax2.grid(True)
  210.  
  211.         fig.tight_layout()
  212.         plt.show(block=False)
  213.  
  214. class Example(QWidget):
  215.  
  216.     def __init__(self):
  217.         super().__init__()
  218.  
  219.         self.edits = {}
  220.         self.currentY = 0
  221.         self.initUI()
  222.  
  223.     def addLabelEditWidget(self, name):
  224.         label = QLabel(self)
  225.         label.setText(inputFields[name].text)
  226.         label.setFont(QFont("Times", 15))
  227.  
  228.         edit = QLineEdit(self)
  229.         self.edits[name] = edit
  230.  
  231.         self.layout().addWidget(label, self.currentY, 0)
  232.         self.layout().addWidget(edit, self.currentY, 1)
  233.         self.currentY += 1
  234.  
  235.     def addBlockCaption(self, text):
  236.         label = QLabel(self)
  237.         label.setText(text)
  238.         label.setFont(QFont("Times", 13, QFont.Bold))
  239.  
  240.         self.layout().addWidget(label, self.currentY, 0)
  241.         self.currentY += 1
  242.  
  243.     def addFormula(self, formula, _fontsize, _x, _horizonalalignment, _verticalalignment):
  244.         bg = self.palette().window().color()
  245.         cl = (bg.redF(), bg.greenF(), bg.blueF())
  246.         fig = Figure(edgecolor=cl, facecolor=cl)
  247.  
  248.         canvas = FigureCanvasQTAgg(fig)
  249.         self.layout().addWidget(canvas, self.currentY, 0, self.currentY, 0)
  250.         self.currentY += 1
  251.  
  252.         fig.clear()
  253.         fig.suptitle(
  254.             formula,
  255.             fontsize = _fontsize,
  256.             x=_x,
  257.             horizontalalignment=_horizonalalignment,
  258.             verticalalignment=_verticalalignment)
  259.         canvas.draw()
  260.  
  261.     def addDescription(self):
  262.         main_formula = (
  263.             r'$\dfrac{1}{\lambda} = '
  264.             r'-2 \log_{10}  \left[ \left( \frac{2.8\ V_{пор}^*}{V \sqrt{\lambda}} \right) ^ {\beta\ /\ 5.75}'
  265.             r'\left( \frac{2.51}{Re \sqrt{\lambda}} + \frac{\Delta_э}{3.7 d} \right) \right]$'
  266.         )
  267.  
  268.         self.addFormula(main_formula, 14, 0.5, 'center', 'top')
  269.  
  270.         legend_formula = (
  271.             r'$\lambda$ - коэффициент трения'
  272.             '\n'
  273.             r'$V_{пор}^*$ - пороговая динамическая скорость'
  274.             '\n'
  275.             r'$V$ - средняя скорость движения жидкости в трубопроводе'
  276.             '\n'
  277.             r'$Re$ - число Рейнольдса'
  278.             '\n'
  279.             r'$d$ - диаметр трубопровода'
  280.             '\n'
  281.             r'$\Delta_э$ - шероховатость трубопровода'
  282.             '\n'
  283.             r'$\beta = Z * C$, где C - объемная концентрация присадки'
  284.         )
  285.  
  286.         self.addFormula(legend_formula, 11, 0, 'left', 'top')
  287.  
  288.     def initUI(self):
  289.  
  290.         grid = QGridLayout(self)
  291.         grid.setSpacing(4)
  292.         grid.setRowMinimumHeight(0, 60)
  293.         grid.setRowMinimumHeight(1, 170)
  294.  
  295.         self.setLayout(grid)
  296.         self.addDescription()
  297.  
  298.         self.addBlockCaption('Параметры трубопровода')
  299.         self.addLabelEditWidget('Epsilon')
  300.         self.addLabelEditWidget('Q')
  301.         self.addLabelEditWidget('d')
  302.         self.addLabelEditWidget('v_n')
  303.         # self.addLabelEditWidget('k')
  304.  
  305.         self.currentY += 1
  306.  
  307.         self.addBlockCaption('Параметры присадки')
  308.         self.addLabelEditWidget('v_p')
  309.         self.addLabelEditWidget('V_por')
  310.         self.addLabelEditWidget('concentration_coefficient')
  311.  
  312.         self.currentY += 1
  313.  
  314.         self.addBlockCaption('Параметры графика')
  315.         self.addLabelEditWidget('c_left_bound')
  316.         self.addLabelEditWidget('c_right_bound')
  317.         self.addLabelEditWidget('c_points_count')
  318.         self.addLabelEditWidget('k_left')
  319.         self.addLabelEditWidget('k_right')
  320.  
  321.         # # Initial values
  322.  
  323.         self.edits['Epsilon'].setText('0.1')
  324.         self.edits['Q'].setText('1.425')
  325.         self.edits['d'].setText('1067')
  326.         self.edits['v_n'].setText('12.2')
  327.         # self.edits['k'].setText('28')
  328.  
  329.         self.edits['v_p'].setText('1700')
  330.         self.edits['V_por'].setText('0.03')
  331.         self.edits['concentration_coefficient'].setText('3000')
  332.  
  333.         self.edits['c_left_bound'].setText('0')
  334.         self.edits['c_right_bound'].setText('150')
  335.         self.edits['c_points_count'].setText('30')
  336.         self.edits['k_left'].setText('28')
  337.         self.edits['k_right'].setText('321')
  338.  
  339.         # # Buttons
  340.  
  341.         btn = QPushButton('Построить график', self)
  342.         btn.clicked.connect(self.showDialog)
  343.         self.layout().addWidget(btn, self.currentY, 0, self.currentY, 0)
  344.  
  345.         self.setWindowTitle('Применение противотурбулентных присадок')
  346.         self.resize(510, 400)
  347.         self.show()
  348.         self.center()
  349.  
  350.     def exception(self, text):
  351.         self.msg = QMessageBox.about(self, "Ошибка", text)
  352.  
  353.     def showDialog(self):
  354.         try:
  355.             eq = Equation()
  356.             for key in inputFields.keys():
  357.                 eq.setData(key, self.edits[key].text())
  358.  
  359.             progressBar = QProgressDialog('Построение графика', 'Отменить', 0, 0, self)
  360.             progressBar.setWindowTitle('Ожидание')
  361.             progressBar.setWindowModality(QtCore.Qt.WindowModal)
  362.             progressBar.canceled.connect(progressBar.close)
  363.             progressBar.setMinimumDuration(100)
  364.  
  365.             progressBar.show()
  366.             eq.showPlot(progressBar)
  367.             progressBar.hide()
  368.  
  369.         except Exception as e:
  370.             self.exception(str(e))
  371.  
  372.     def center(self):
  373.         qr = self.frameGeometry()
  374.         cp = QDesktopWidget().availableGeometry().center()
  375.         qr.moveCenter(cp)
  376.         self.move(qr.topLeft())
  377.  
  378. if __name__ == '__main__':
  379.     QApplication.processEvents()
  380.     app = QApplication(sys.argv)
  381.     ex = Example()
  382.     sys.exit(app.exec_())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement