Source code for tools.wizard

#!/usr/bin/python3
# -*- coding: utf-8 -*-

'''Pychemqt, Chemical Engineering Process simulator
Copyright (C) 2009-2025, Juan José Gómez Romera <jjgomera@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.


Module with wizard project configuration, it's launched when it creates a new
pychemqt project to configure:

* :doc:`Component list </tools.UI_confComponents>`
* :doc:`Thermodynamic properties methods </tools.UI_confThermo>`
* :doc:`Transport properties methods </tools.UI_confTransport>`
* :doc:`Units prefered </tools.UI_confUnits>`

The wizard can be launch whanever you want using its menu entry

The module include all related wizard functionality:

* :func:`auto`: Function to calculate autovalues for thermo calculation
* :class:`AutoDialog`: Dialog to define values for auto function, this \
dialog can be launch in thermo page of wizard to autoselect a good stimation \
of values
* :class:`Wizard`: Wizard dialog for project configuration


API reference
-------------
'''

from configparser import ConfigParser
import os

from numpy import count_nonzero

from lib import mEoS, gerg, refProp, coolProp, EoS
from lib.bip import Kij
from lib.compuestos import Componente
from lib.config import conf_dir
from lib.unidades import Temperature, Pressure
from tools import (UI_confComponents, UI_confTransport, UI_confThermo,
                   UI_confUnits, UI_confResolution)
from tools.qt import QtGui, QtWidgets
from UI.widgets import Entrada_con_unidades


[docs] def auto(tmin=None, tmax=None, pmin=None, pmax=None, components=None): """Function to calculate autovalues for thermo calculation tmin: Stimated minimum temperature from project tmax: Stimated maximum temperature from project pmin: Stimated minimum pressure from project pmax: Stimated maximum pressure from project Components: array with ids numbers component from project""" if components is None: components = [] config = ConfigParser() config = UI_confThermo.UI_confThermo_widget.default(config) GERG_available = True REFPROP_available = True for idx in components: if idx not in gerg.id_GERG: GERG_available = False if idx not in refProp.__all__: REFPROP_available = False if len(components) == 1 and components[0] == 62: config.set("Thermo", "iapws", "True") if os.environ["freesteam"] == "True": config.set("Thermo", "freesteam", "True") if len(components) == 1 and components[0] in mEoS.id_mEoS: config.set("Thermo", "MEoS", "True") if os.environ["CoolProp"] == "True" and len(components) == 1 and \ components[0] in coolProp.all__: config.set("Thermo", "coolprop", "True") if os.environ["refprop"] == "True" and REFPROP_available: config.set("Thermo", "refprop", "True") if GERG_available: config.set("Thermo", "GERG", "True") # TODO: add EOS configuration # Decission tree for EoS # Carlson, E.C. # Don't Gamble with Physical Properties for Simulations cmps = [Componente(cmp) for cmp in components] polar = False for cmp in cmps: if cmp.dipole: polar = True break # TODO: Add pseudocompound properties to database to identifier it # For now consider all user defined compound as pseudocomponent real = True for cmp in cmps: if cmp.id > 10000: real = False break # TODO: Add electrolytes detection logic electrolyte = False if polar: if electrolyte: pass else: # Figure 2 pass elif real: # Find equation with more bip in database ids = [cmp.id for cmp in cmps] bip_pr = count_nonzero(Kij(ids, EOS="PR")) bip_srk = count_nonzero(Kij(ids, EOS="SRK")) bip_apisrk = count_nonzero(Kij(ids, EOS="APISRK")) bip_bwrs = count_nonzero(Kij(ids, EOS="BWRS")) if bip_bwrs > max(bip_apisrk, bip_srk, bip_pr): idx = EoS.K.index(EoS.BWRS.BWRS) elif bip_apisrk > max(bip_srk, bip_pr): idx = EoS.K.index(EoS.Cubic.SRKAPI) elif bip_srk > bip_pr: idx = EoS.K.index(EoS.Cubic.SRK) else: idx = EoS.K.index(EoS.Cubic.PR) config.set("Thermo", "k", str(idx)) else: idx = EoS.K.index(EoS.Grayson_Streed) config.set("Thermo", "k", str(idx)) return config
[docs] class AutoDialog(QtWidgets.QDialog): """Dialog to input value for auto thermal function"""
[docs] def __init__(self, parent=None): super().__init__(parent) layout = QtWidgets.QGridLayout(self) layout.addWidget(QtWidgets.QLabel(self.tr("T<sub>min</sub>")), 1, 1) self.Tmin = Entrada_con_unidades(Temperature) layout.addWidget(self.Tmin, 1, 2) layout.addWidget(QtWidgets.QLabel(self.tr("T<sub>max</sub>")), 2, 1) self.Tmax = Entrada_con_unidades(Temperature) layout.addWidget(self.Tmax, 2, 2) layout.addWidget(QtWidgets.QLabel(self.tr("P<sub>min</sub>")), 3, 1) self.Pmin = Entrada_con_unidades(Pressure) layout.addWidget(self.Pmin, 3, 2) layout.addWidget(QtWidgets.QLabel(self.tr("P<sub>max</sub>")), 4, 1) self.Pmax = Entrada_con_unidades(Pressure) layout.addWidget(self.Pmax, 4, 2) self.buttonBox = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.StandardButton.Cancel | QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) layout.addWidget(self.buttonBox, 5, 1, 1, 2)
[docs] class Wizard(QtWidgets.QWizard): """Wizard dialog for project configuration"""
[docs] def __init__(self, config=None, parent=None): super().__init__(parent) self.config = config self.setWindowTitle(self.tr("Configuration wizard...")) self.setOptions(QtWidgets.QWizard.WizardOption.ExtendedWatermarkPixmap | QtWidgets.QWizard.WizardOption.IndependentPages | QtWidgets.QWizard.WizardOption.HaveCustomButton1) self.setWizardStyle(QtWidgets.QWizard.WizardStyle.ModernStyle) botonAuto = QtWidgets.QPushButton(self.tr("Auto")) botonAuto.setToolTip(self.tr( "Choose good values from project components and conditions")) self.setButton(QtWidgets.QWizard.WizardButton.CustomButton1, botonAuto) self.customButtonClicked.connect(self.auto) page1_welcome = QtWidgets.QWizardPage() page1_welcome.setTitle(self.tr("Welcome")) page1_welcome.setSubTitle(self.tr( "That's the configuration wizard of a new project from pychemqt")) page1_welcome.setPixmap( QtWidgets.QWizard.WizardPixmap.LogoPixmap, QtGui.QPixmap( os.path.join(os.environ["pychemqt"], "images", "pychemqt_98.png"))) page1_welcome.setPixmap( QtWidgets.QWizard.WizardPixmap.WatermarkPixmap, QtGui.QPixmap( os.path.join(os.environ["pychemqt"], "images", "logo_2.jpg"))) lyt = QtWidgets.QVBoxLayout(page1_welcome) lyt.addWidget(QtWidgets.QLabel(self.tr( """<html><body> This wizard let's you configure all parameters necessary in a pychemqt's project<br> All options will can be changed later using the options in menu Edit, and this wizard<br> can be run at any time later.<br> These are the options you must expecific next:<br> <ul> <li>Component list</li> <li>Thermodinamic properties</li> <li>Transport properties</li> <li>Engineering units preferred</li> </ul> <body></html>"""))) self.addPage(page1_welcome) page2_components = QtWidgets.QWizardPage() page2_components.setTitle(self.tr("Define components")) page2_components.setSubTitle(self.tr("Add componentes from database")) page2_components.setPixmap( QtWidgets.QWizard.WizardPixmap.LogoPixmap, QtGui.QPixmap( os.path.join(os.environ["pychemqt"], "images", "pychemqt_98.png"))) lyt = QtWidgets.QVBoxLayout(page2_components) self.componentes = UI_confComponents.UI_confComponents_widget(config) self.componentes.componentChanged.connect(self.button( QtWidgets.QWizard.WizardButton.NextButton).setEnabled) lyt.addWidget(self.componentes) self.addPage(page2_components) page3_thermo = QtWidgets.QWizardPage() page3_thermo.setTitle(self.tr("Define thermodynamics procedures")) page3_thermo.setSubTitle(self.tr( "The thermodynamics properties are the basic of " "pychemqt, a bad selection would be disastrous for the results")) page3_thermo.setPixmap( QtWidgets.QWizard.WizardPixmap.LogoPixmap, QtGui.QPixmap( os.path.join(os.environ["pychemqt"], "images", "pychemqt_98.png"))) lyt = QtWidgets.QVBoxLayout(page3_thermo) self.thermo = UI_confThermo.UI_confThermo_widget(config) lyt.addWidget(self.thermo) self.addPage(page3_thermo) page4_transport = QtWidgets.QWizardPage() page4_transport.setTitle(self.tr("Define transport procedures")) page4_transport.setSubTitle(self.tr( "The transport properties are important too for good simulation " "results")) page4_transport.setPixmap(QtWidgets.QWizard.WizardPixmap.LogoPixmap, QtGui.QPixmap( os.path.join(os.environ["pychemqt"], "images", "pychemqt_98.png"))) lyt = QtWidgets.QVBoxLayout(page4_transport) self.transport = UI_confTransport.UI_confTransport_widget(config) lyt.addWidget(self.transport) self.addPage(page4_transport) page5_units = QtWidgets.QWizardPage() page5_units.setTitle(self.tr("Define preferred units")) page5_units.setSubTitle(self.tr( "The preferred units are not necessary for the simulation, " "but a good election let you only focus in simulation")) page5_units.setPixmap(QtWidgets.QWizard.WizardPixmap.LogoPixmap, QtGui.QPixmap( os.path.join(os.environ["pychemqt"], "images", "pychemqt_98.png"))) lyt = QtWidgets.QVBoxLayout(page5_units) self.units = UI_confUnits.UI_confUnits_widget(config) lyt.addWidget(self.units) self.addPage(page5_units) self.currentIdChanged.connect(self.checkComponents)
[docs] def checkComponents(self, idx): """Component window can be only passed with any added components""" if idx == 1: self.button(QtWidgets.QWizard.WizardButton.NextButton).setEnabled(len( self.componentes.indices) != 0) self.button(QtWidgets.QWizard.WizardButton.CustomButton1).setVisible(idx == 2)
[docs] def auto(self): """Dialog to define project parameter to auto thermal configuration""" dialogo = AutoDialog() if dialogo.exec(): tmin = dialogo.Tmin.value tmax = dialogo.Tmax.value pmin = dialogo.Pmin.value pmax = dialogo.Pmax.value config = auto(tmin, tmax, pmin, pmax, self.componentes.indices) self.thermo.setConfig(config)
@property def value(self): """Return config dict defined in wizard""" config = self.componentes.value(self.config) config = self.thermo.value(config) config = self.transport.value(config) config = self.units.value(config) if not config.has_section("PFD"): config.add_section("PFD") Preferences = ConfigParser() Preferences.read(conf_dir+"pychemqtrc") config.set("PFD", "x", Preferences.get("PFD", "x")) config.set("PFD", "y", Preferences.get("PFD", "y")) return config
[docs] @classmethod def default(cls): """Set default config""" config = ConfigParser() config = UI_confComponents.UI_confComponents_widget.default(config) config = UI_confThermo.UI_confThermo_widget.default(config) config = UI_confTransport.UI_confTransport_widget.default(config) config = UI_confUnits.UI_confUnits_widget.default(config) config = UI_confResolution.UI_confResolution_widget.default(config) return config
if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) ui = Wizard() ui.show() sys.exit(app.exec())