daily pastebin goal
44%
SHARE
TWEET

Untitled

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