Ejemplo n.º 1
0
class App(QWidget):
    def __init__(self):
        super().__init__()
        self.title = 'Thermodynamic data'

        qd = QDesktopWidget()
        screen = qd.screenGeometry(qd)
        width = 600
        height = 300

        x = screen.width() / 2 - width / 2
        y = screen.height() / 2 - height / 2

        self.width = width
        self.height = height
        self.left = x
        self.top = y
        self.ignore_events = False
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        self.tableView1 = QTableView()
        self.tableWidget1 = QTableWidget()
        self.model = thTableModel()
        self.cas_filter = QLineEdit()
        self.name_filter = QLineEdit()
        self.formula_filter = QLineEdit()
        self.phase_filter = QComboBox()
        self.delete_selected_button = QPushButton()
        self.copy_selected_button = QPushButton()
        self.phases_vol_button = QPushButton()
        self.temp_text = QLineEdit()
        self.plot_window = PlotWindow()
        self.cp_button = QPushButton()
        self.psat_button = QPushButton()

        self.tableView1.setModel(self.model)
        self.tableWidget1.setColumnCount(
            self.tableView1.model().columnCount() + 1 + 1 + 1 + 1 + 1)
        self.widget_col_names = ['z_i', 'h_ig', 's_ig', 'g_ig', 'cp_ig'
                                 ] + self.tableView1.model().column_names
        self.widget_col_units = ['-', 'J/mol', 'J/mol/K', 'J/mol', 'J/mol/K'
                                 ] + self.tableView1.model().column_units
        self.widget_col_names_units = [
            self.widget_col_names[i] + '\n' + self.widget_col_units[i]
            for i in range(len(self.widget_col_names))
        ]
        self.tableWidget1.setHorizontalHeaderLabels(
            self.widget_col_names_units)
        self.phase_filter.addItems(['', 'G', 'L', 'S', 'C'])
        self.tableWidget1.setEnabled(False)
        self.tableWidget1.setSelectionBehavior(QTableWidget.SelectRows)
        self.tableWidget1.installEventFilter(self)
        self.delete_selected_button.setText('delete selected')
        self.copy_selected_button.setText('copy selected')
        self.phases_vol_button.setText('ph, v')
        self.temp_text.setValidator(QDoubleValidator(0, 6000, 16))
        self.temp_text.setPlaceholderText('1000 K')

        # Add box layout, add table to box layout and add box layout to widget
        self.layout = QGridLayout()
        self.layout.addWidget(self.tableView1, 1, 1, 1, 4)
        self.layout.addWidget(self.cas_filter, 3, 1, 1, 1)
        self.layout.addWidget(self.name_filter, 3, 2, 1, 1)
        self.layout.addWidget(self.formula_filter, 3, 3, 1, 1)
        self.layout.addWidget(self.phase_filter, 3, 4, 1, 1)
        self.layout.addWidget(QLabel('find by: cas'), 2, 1, 1, 1)
        self.layout.addWidget(QLabel('name'), 2, 2, 1, 1)
        self.layout.addWidget(QLabel('formula'), 2, 3, 1, 1)
        self.layout.addWidget(QLabel('phase'), 2, 4, 1, 1)
        self.layout.addWidget(QLabel('selection'), 4, 1, 1, 4)
        self.layout.addWidget(self.tableWidget1, 5, 1, 1, 4)
        self.layout.addWidget(self.delete_selected_button, 6, 4, 1, 1)
        self.layout.addWidget(self.copy_selected_button, 6, 1, 1, 1)
        self.layout.addWidget(self.phases_vol_button, 6, 2, 1, 1)
        self.layout.addWidget(self.temp_text, 6, 3, 1, 1)

        self.setLayout(self.layout)

        for item in [self.cas_filter, self.name_filter, self.formula_filter]:
            item.textChanged.connect(self.apply_filters)
        self.phase_filter.currentTextChanged.connect(self.apply_filters)
        self.tableView1.selectionModel().selectionChanged.connect(
            partial(self.add_selection_to_widget))
        self.tableWidget1.cellChanged.connect(partial(self.update_props))
        self.delete_selected_button.clicked.connect(
            partial(self.delete_selected))
        self.copy_selected_button.clicked.connect(partial(self.copy_selection))
        self.phases_vol_button.clicked.connect(partial(self.phases_vol))
        self.temp_text.editingFinished.connect(partial(self.update_temp))
        #self.tableView1.horizontalHeader().setClickable(False)

        self.props_i = self.tableView1.model().df.iloc[[]]
        self.props_i['z_i'] = zeros(0)
        self.props_i['h_ig'] = zeros(0)
        self.props_i['s_ig'] = zeros(0)
        self.props_i['g_ig'] = zeros(0)
        self.props_i['cp_ig'] = zeros(0)

        # Show widget
        self.show()

    def apply_filters(self):
        cas_filter = self.cas_filter.text().upper().strip().replace(' ', '')
        name_filter = self.name_filter.text().upper().strip()
        formula_filter = self.formula_filter.text().upper().strip()
        phase_filter = self.phase_filter.currentText()
        self.model.apply_filter(cas_filter, name_filter, formula_filter,
                                phase_filter)

    def add_selection_to_widget(self, selected, deselected):
        # indexes = self.tableView1.selectedIndexes()
        indexes = selected.indexes()
        index = indexes[0]
        column_of_cas = self.tableView1.model().column_names.index('cas_no')
        column_of_phase = self.tableView1.model().column_names.index('phase')
        phase = self.tableView1.model().index(index.row(),
                                              column_of_phase).data()
        cas = self.tableView1.model().index(index.row(), column_of_cas).data()
        already_in_table = False
        for item in self.tableWidget1.findItems(cas, Qt.MatchExactly):
            if phase == self.tableWidget1.item(
                    item.row(), column_of_phase + 1 + 1 + 1 + 1 + 1).text():
                already_in_table = True
        if not already_in_table:
            row_index = int(self.tableView1.model().headerData(
                index.row(), Qt.Vertical))
            column_names = self.tableView1.model().column_names
            header_to_add = QTableWidgetItem(str(row_index))

            # save df with new props
            z_i_orig = self.props_i['z_i']
            h_ig_orig = self.props_i['h_ig']
            s_ig_orig = self.props_i['s_ig']
            g_ig_orig = self.props_i['g_ig']
            cp_ig_orig = self.props_i['cp_ig']
            index_orig = self.props_i.index
            self.props_i = self.tableView1.model().df.loc[[
                int(self.tableWidget1.verticalHeaderItem(i).text())
                for i in range(self.tableWidget1.rowCount())
            ] + [row_index], :]
            self.props_i['z_i'] = zeros(len(self.props_i))
            self.props_i['h_ig'] = zeros(len(self.props_i))
            self.props_i['s_ig'] = zeros(len(self.props_i))
            self.props_i['g_ig'] = zeros(len(self.props_i))
            self.props_i['cp_ig'] = zeros(len(self.props_i))
            self.props_i.loc[index_orig, 'z_i'] = z_i_orig
            self.props_i.loc[index_orig, 'h_ig'] = h_ig_orig
            self.props_i.loc[index_orig, 's_ig'] = s_ig_orig
            self.props_i.loc[index_orig, 'g_ig'] = g_ig_orig
            self.props_i.loc[index_orig, 'cp_ig'] = cp_ig_orig

            self.props_i.loc[row_index, 'z_i'] = float(0)

            # add item to widget
            self.tableWidget1.setRowCount(self.tableWidget1.rowCount() + 1)
            self.tableWidget1.setVerticalHeaderItem(
                self.tableWidget1.rowCount() - 1, header_to_add)
            for i in range(len(column_names)):
                # columns in TableWidget shifted by 1+1+1+1+1 vs. Tableview due to first columns z_i, h_ig, s_ig, g_ig, cp_ig
                data = self.tableView1.model().index(index.row(), i).data()
                if isinstance(data, str) or data is None:
                    item_to_add = QTableWidgetItem(data)
                else:
                    item_to_add = QTableWidgetItem(locale.str(data))
                item_to_add.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                                     | Qt.ItemIsEditable)
                self.tableWidget1.setItem(self.tableWidget1.rowCount() - 1,
                                          i + 1 + 1 + 1 + 1 + 1, item_to_add)

            # additional column with z_i
            item_to_add = QTableWidgetItem(locale.str(0))
            item_to_add.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                                 | Qt.ItemIsEditable)
            self.tableWidget1.setItem(self.tableWidget1.rowCount() - 1, 0,
                                      item_to_add)

        if len(indexes) > 0 or self.tableWidget1.rowCount() > 0:
            self.tableWidget1.setEnabled(True)

    def update_props(self, row, col):
        if col == 0:
            # change z_i
            df_index = int(self.tableWidget1.verticalHeaderItem(row).text())
            new_value = float(
                self.tableWidget1.item(row, col).text().replace(',', '.'))
            self.props_i.loc[df_index, 'z_i'] = new_value
        else:
            pass

    def update_temp(self):
        if self.temp_text.hasAcceptableInput():
            self.temp_text.setPlaceholderText(self.temp_text.text() + ' K')
            t = float(self.temp_text.text().replace(',', '.'))  # K
            self.temp_text.clear()
        else:
            t = 1000  # K
            self.temp_text.clear()
        mm_i = (self.props_i['poling_molwt'] / 1000).tolist()  # kg/mol
        tc_i = self.props_i['poling_tc'].tolist()  # K
        pc_i = (self.props_i['poling_pc'] * 1e5).tolist()  # Pa
        omega_i = self.props_i['poling_omega'].tolist()
        vc_i = (self.props_i['poling_vc'] * 10**-6).tolist()  # m^3/mol
        delhf0_poling = (self.props_i['poling_delhf0'] *
                         1000).tolist()  # J/mol
        delgf0_poling = (self.props_i['poling_delgf0'] *
                         1000).tolist()  # J/mol
        delsf0_poling = [(delhf0_poling[i] - delgf0_poling[i]) / 298.15
                         for i in range(len(self.props_i))]  # J/mol/K
        a_low = [
            self.props_i['a' + str(i) + '_low'].tolist()
            for i in range(1, 7 + 1)
        ]
        a_high = [
            self.props_i['a' + str(i) + '_high'].tolist()
            for i in range(1, 7 + 1)
        ]

        cp_r_low = [
            sum([a_low[j][i] * t**j for j in range(4 + 1)])
            for i in range(len(self.props_i))
        ]  # cp/R
        cp_r_high = [
            sum([a_high[j][i] * t**j for j in range(4 + 1)])
            for i in range(len(self.props_i))
        ]  # cp/R

        if t > 1000:  # poly a_low is for 200 - 1000 K; a_high is for 1000 - 6000 K
            a = a_high
            cp_ig = [8.3145 * cp_r_high[i]
                     for i in range(len(self.props_i))]  # J/mol/K
        else:
            a = a_low
            cp_ig = [8.3145 * cp_r_low[i]
                     for i in range(len(self.props_i))]  # J/mol/K

        s_cp_r_dt = [
            sum([1 / (j + 1) * a[j][i] * t**(j + 1)
                 for j in range(4 + 1)]) - sum([
                     1 / (j + 1) * a_low[j][i] * 298.15**(j + 1)
                     for j in range(4 + 1)
                 ]) for i in range(len(self.props_i))
        ]  # int(Cp/R*dT,298,15K,T)
        # int(Cp/R/T*dT,298.15K,T)
        s_cp_r_t_dt = [
            a[0][i] * log(t) + a[6][i] +
            sum([1 / (j) * a[j][i] * t**(j) for j in range(1, 3 + 1)])
            for i in range(len(self.props_i))
        ]  # int(Cp/(RT)*dT,0,T)

        h_ig = [
            delhf0_poling[i] + 8.3145 * s_cp_r_dt[i]
            for i in range(len(self.props_i))
        ]
        s_ig = [8.3145 * s_cp_r_t_dt[i] for i in range(len(self.props_i))]
        g_ig = [h_ig[i] - t * s_ig[i] for i in range(len(self.props_i))]

        for i in range(len(self.props_i)):
            for j, col in enumerate([h_ig, s_ig, g_ig, cp_ig]):
                #print(col)
                item_to_add = QTableWidgetItem(locale.str(col[i]))
                item_to_add.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                                     | Qt.ItemIsEditable)
                self.tableWidget1.setItem(i, j + 1, item_to_add)

    def copy_selection(self):
        selection = self.tableWidget1.selectedIndexes()
        if selection:
            rows = sorted(index.row() for index in selection)
            columns = range(len(self.widget_col_names))
            rowcount = rows[-1] - rows[0] + 1
            colcount = columns[-1] - columns[0] + 1 + 1
            table = [[''] * colcount for _ in range(rowcount + 1)]
            table[0] = []
            for i in range(len(self.widget_col_names)):
                text_to_add = self.widget_col_names[
                    i] + '/(' + self.widget_col_units[i] + ')'
                table[0] += [text_to_add]
            for index in selection:
                row = index.row() - rows[0]
                column = index.column() - columns[0]
                table[row + 1][column] = index.data().replace(
                    chr(34), ''
                )  # ensure string can be read as csv by removing quotation mark (ascii character 34)
            table = table + [['T=' + self.temp_text.placeholderText()] +
                             ['' for _ in range(colcount - 1)]]
            stream = io.StringIO()
            csv.writer(stream, delimiter=';',
                       quoting=csv.QUOTE_NONE).writerows(table)
            QApplication.clipboard().setText(stream.getvalue())

    def eventFilter(self, source, event):
        if self.ignore_events:
            pass
        elif (event.type() == QEvent.KeyPress
              and event.matches(QKeySequence.Copy)):
            self.copy_selection()
            return True
        elif (event.type() == QEvent.KeyPress
              and event.matches(QKeySequence.Delete)):
            if len(self.tableWidget1.selectedIndexes()) > 1:
                self.delete_selected()
            return True
        return super(App, self).eventFilter(source, event)

    def delete_selected(self):
        if len(self.tableWidget1.selectedIndexes()) > 0:
            while len(self.tableWidget1.selectedIndexes()) > 0:
                current_row = self.tableWidget1.selectedIndexes()[0].row()
                row_index = int(
                    self.tableWidget1.verticalHeaderItem(current_row).text())
                self.tableWidget1.removeRow(current_row)
                self.props_i = self.props_i.drop([row_index])
            self.tableWidget1.selectRow(current_row)
            if self.tableWidget1.rowCount() == 0:
                self.tableWidget1.setEnabled(False)

    def phases_vol(self):
        self.plot_window.show()
        t = linspace(60, 220, 10)
        p = 1.01325  # bar
        phase_fraction = empty_like(t)
        v_l = empty_like(t)
        v_v = empty_like(t)
        z_i = self.props_i['z_i']
        # normalize z_i
        sum_z_i = sum(z_i)
        if sum_z_i <= 0:
            z_i = 1 / len(z_i) * ones(len(z_i))
            z_i = z_i.tolist()
        elif sum_z_i != 1.0:
            z_i = z_i / sum_z_i
            z_i = z_i.to_list()
        else:
            z_i = z_i.to_list()
        mm_i = (self.props_i['poling_molwt'] / 1000).tolist()  # kg/mol
        tc_i = self.props_i['poling_tc'].tolist()  # K
        pc_i = (self.props_i['poling_pc']).tolist()  # bar
        omega_i = self.props_i['poling_omega'].tolist()
        vc_i = (self.props_i['poling_vc'] * 10**-6).tolist()  # m^3/mol
        state = State(t[0], p, z_i, mm_i, tc_i, pc_i, omega_i, 'pr')

        for i in range(len(t)):
            state.set_t(t[i])
            phase_fraction[i] = state.v_f
            v_l[i] = state.v_l
            v_v[i] = state.v_v
        self.plot_window.ax[0].plot(t, phase_fraction)
        self.plot_window.ax[0].set_xlabel('T / K')
        self.plot_window.ax[0].set_xlabel('V / F')
        self.plot_window.ax[1].semilogy(t, v_l, label='v_l')
        self.plot_window.ax[1].semilogy(t, v_v, label='v_v')
        self.plot_window.ax[1].set_xlabel('T / K')
        self.plot_window.ax[1].set_xlabel(r'$\frac{V}{m^3 / mol}$')
        self.plot_window.ax[1].legend()
        self.plot_window.fig.tight_layout()