Source code for plots.heatTransfer

#!/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/>.'''


###############################################################################
# Heat Transfer chart
###############################################################################


import os
from math import pi

from matplotlib import image
from numpy import arange, logspace, arctan
from tools.qt import QtWidgets, translate

from lib.config import IMAGE_PATH
from lib.heatTransfer import (effectiveness, TemperatureEffectiveness,
                              CorrectionFactor, Fi)

from plots.ui import Chart


[docs] class ChartHeat(Chart): """Dialog to implement general heat exchanger plot""" flujo = [] MIX = ("Cmin", "Cmax") locImage = None locLogo = None
[docs] def customUI(self): """Define custom UI element for heat transfer plot""" self.butonConf.setEnabled(False) self.butonCalc.setEnabled(False) lyt = QtWidgets.QHBoxLayout() lyt.addWidget(QtWidgets.QLabel(self.tr("Flow Arrangement"))) self.flow = QtWidgets.QComboBox() for text in self.flujo: self.flow.addItem(text[0]) self.flow.currentIndexChanged.connect(self.plot) lyt.addWidget(self.flow) self.mixed = QtWidgets.QComboBox() for text in self.MIX: self.mixed.addItem(text) self.mixed.currentIndexChanged.connect(self.plot) lyt.addWidget(self.mixed) self.exact = QtWidgets.QCheckBox(self.tr("Use exact correlation")) self.exact.toggled.connect(self.plot) lyt.addWidget(self.exact) lyt.addItem(QtWidgets.QSpacerItem( 10, 10, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)) self.layout().addLayout(lyt, 0, 1, 1, 3) self.image = self.plt.fig.add_axes(self.locImage, anchor='SW')
[docs] def set_image(self, flux): """Draw flux image in plot""" self.image.clear() logo = image.imread(os.path.join( IMAGE_PATH, "equipment", "heat transfer", flux)+".png") self.image.imshow(logo, alpha=0.9) self.image.axis('off')
[docs] class Efectividad(ChartHeat): """Heat Exchanger effectiveness plot""" title = translate("Efectividad", "Heat Exchanger effectiveness") flujo = [ (translate("Efectividad", "Counterflow"), "CF"), (translate("Efectividad", "Parallelflow"), "PF"), (translate("Efectividad", "Crossflow, both fluids unmixed"), "CrFunMix"), (translate("Efectividad", "Crossflow, one fluid mixed"), "CrFSMix"), (translate("Efectividad", "Crossflow, both fluids mixed"), "CrFMix"), (translate("Efectividad", "1-2 pass shell and tube exchanger"), "1-2TEMAE")] locImage = (0.7, 0.15, 0.2, 0.2) locLogo = (0.13, 0.77, 0.1, 0.1)
[docs] def plot(self): self.plt.ax.clear() self.plt.ax.set_xlim(0, 6) self.plt.ax.set_ylim(0, 1) title = self.tr("Heat Transfer effectiveness") self.plt.ax.set_title(title, size='12') self.plt.ax.set_xlabel("NTU", size='12') self.plt.ax.set_ylabel("ε", size='14') index = self.flow.currentIndex() flujo = self.flujo[index][1] self.set_image(flujo) self.mixed.setVisible(flujo == "CrFSMix") self.exact.setVisible(flujo == "CrFunMix") kw = {} if flujo == "CrFSMix": kw["mixed"] = str(self.mixed.currentText()) if flujo == "CrFunMix": kw["exact"] = self.exact.isChecked() C = [0, 0.2, 0.4, 0.6, 0.8, 1.] NTU = arange(0, 6.1, 0.1) for ci in C: e = [0] for N in NTU[1:]: e.append(effectiveness(N, ci, flujo, **kw)) self.plt.plot(NTU, e, "k") # Calculate angle for annotation text xmin, xmax = self.plt.ax.get_xlim() ymin, ymax = self.plt.ax.get_ylim() f_x = (NTU[40]-NTU[35])/(xmax-xmin) f_y = (e[40]-e[35])/(ymax-ymin) angle = arctan(f_y/f_x)*360/2/pi self.plt.ax.annotate( f"C*={ci:0.1f}", (NTU[35], e[35]), rotation=angle, size="x-small", ha="left", va="bottom") self.plt.draw()
[docs] class TemperatureEfectividad(ChartHeat): """Heat exchanger temperature-effectiveness plot""" title = translate("TemperatureEfectividad", "Heat Exchanger temperature effectiveness") flujo = [ (translate("TemperatureEfectividad", "Counterflow"), "CF"), (translate("TemperatureEfectividad", "Parallelflow"), "PF"), (translate("TemperatureEfectividad", "Crossflow, both fluids unmixed"), "CrFunMix"), (translate("TemperatureEfectividad", "Crossflow, one fluid mixed"), "CrFSMix"), (translate("TemperatureEfectividad", "Crossflow, both fluids mixed"), "CrFMix"), (translate("TemperatureEfectividad", "1-2 TEMA E"), "1-2TEMAE"), (translate("TemperatureEfectividad", "1-2 TEMA E, shell fluid divided"), "1-2TEMAE2"), (translate("TemperatureEfectividad", "1-3 TEMA E"), "1-3TEMAE"), (translate("TemperatureEfectividad", "1-4 TEMA E"), "1-4TEMAE"), (translate("TemperatureEfectividad", "1-1 TEMA G"), "1-1TEMAG"), (translate("TemperatureEfectividad", "1-2 TEMA G"), "1-2TEMAG"), (translate("TemperatureEfectividad", "1-1 TEMA H"), "1-1TEMAH"), (translate("TemperatureEfectividad", "1-2 TEMA H"), "1-2TEMAH"), (translate("TemperatureEfectividad", "1-1 TEMA J"), "1-1TEMAJ"), (translate("TemperatureEfectividad", "1-2 TEMA J"), "1-2TEMAJ"), (translate("TemperatureEfectividad", "1-4 TEMA J"), "1-4TEMAJ")] locImage = (0.13, 0.6, 0.15, 0.15) locLogo = (0.13, 0.77, 0.1, 0.1)
[docs] def plot(self): self.plt.ax.clear() self.plt.ax.set_xlim(0.1, 10) self.plt.ax.set_ylim(0, 1) self.plt.ax.set_xscale("log") self.plt.ax.set_title( self.tr("Heat Transfer Temperature Effectiveness"), size='12') self.plt.ax.set_xlabel("NTU", size='12') self.plt.ax.set_ylabel("P", size='14') # self.plt.ax.set_xticklabels([0.1, 1.0, 10]) # xticklabels = [0.2, 0.3, None, 0.5, None, 0.7, None, None, 2.0, 3.0, # None, 5.0, None, 7.0, None, None] # self.plt.ax.set_xticklabels(xticklabels, minor=True) index = self.flow.currentIndex() flujo = self.flujo[index][1] self.set_image(flujo) self.mixed.setVisible(flujo == "CrFSMix") kwargs = {} if flujo == "CrFSMix": kwargs["mixed"] = str(self.mixed.currentText()) R = [0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., 1.2, 1.4, 1.6, 1.8, 2., 2.5, 3., 4., 6., 8., 10., 15.] NTU = logspace(-1.5, 1, 100) for ri in R: e = [0] for N in NTU[1:]: e.append(TemperatureEffectiveness(N, ri, flujo, **kwargs)) self.plt.plot(NTU, e, "k") self.plt.ax.annotate(f"R={ri:0.1f}", (NTU[-1], e[-1]), size="medium", ha="left", va="center") self.plt.draw()
[docs] class F(ChartHeat): """Heat Exchanger correction factor plot""" title = translate("F", "ΔT Correction Factor") flujo = [ (translate("F", "Crossflow, both fluids unmixed"), "CrFunMix"), (translate("F", "Crossflow, one fluid mixed"), "CrFSMix"), (translate("F", "Crossflow, both fluids mixed"), "CrFMix"), (translate("F", "1-2 pass shell and tube exchanger"), "1-2TEMAE")] locImage = (0.13, 0.6, 0.15, 0.15) locLogo = (0.13, 0.77, 0.1, 0.1)
[docs] def plot(self): self.plt.ax.clear() self.plt.ax.set_xlim(0, 1) self.plt.ax.set_ylim(0, 1) title = r"$\Delta T_{ml}$ " + self.tr("Correction Factor") self.plt.ax.set_title(title, size='12') xlabel = "$P=\\frac{T_{1o}-T_{1i}}{T_{2i}-T_{1i}}$" self.plt.ax.set_xlabel(xlabel, size='12') self.plt.ax.set_ylabel("F", size='14') index = self.flow.currentIndex() flujo = self.flujo[index][1] self.set_image(flujo) self.mixed.setVisible(flujo == "CrFSMix") kwargs = {} if flujo == "CrFSMix": kwargs["mixed"] = str(self.mixed.currentText()) R = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., 1.2, 1.4, 1.6, 1.8, 2, 2.5, 3, 4, 6, 8, 10, 15, 20] P = arange(0, 1.01, 0.01) for ri in R: f = [CorrectionFactor(p, ri, flujo, **kwargs) for p in P] self.plt.plot(P, f, "k") # fraccionx=P[90]-P[80] # fracciony=f[90]-f[80] # try: # angle=arctan(fracciony/fraccionx)*360/2/pi # except ZeroDivisionError: # angle=90 # self.plt.ax.annotate( # "R=%0.1f" %ri, (P[90], f[90]), rotation=angle, size="medium", # horizontalalignment="left", verticalalignment="bottom") self.plt.draw()
[docs] class Phi(ChartHeat): """Heat Exchanger correction factor plot""" title = translate("Phi", "ψ") flujo = [ # (translate("Phi", "Crossflow, both fluids unmixed"), "CrFunMix"), # (translate("Phi", "Crossflow, one fluid mixed"), "CrFSMix"), # (translate("Phi", "Crossflow, both fluids mixed"), "CrFMix"), (translate("Phi", "1-2 pass shell and tube exchanger"), "1-2TEMAE")] locImage = (0.75, 0.6, 0.15, 0.15) locLogo = (0.8, 0.77, 0.1, 0.1)
[docs] def plot(self): self.plt.ax.clear() self.plt.ax.set_xlim(0, 1) self.plt.ax.set_ylim(0, 1) title = r"$\Delta T_{ml}$ " + self.tr(" Correction Factor") self.plt.ax.set_title(title, size='12') self.plt.ax.set_xlabel( "$P=\\frac{T_{1o}-T_{1i}}{T_{2i}-T_{1i}}$", size='12') self.plt.ax.set_ylabel("F", size='14') index = self.flow.currentIndex() flujo = self.flujo[index][1] self.set_image(flujo) self.mixed.setVisible(flujo == "CrFSMix") kwargs = {} if flujo == "CrFSMix": kwargs["mixed"] = str(self.mixed.currentText()) R = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., 1.2, 1.4, 1.6, 1.8, 2, 2.5, 3, 4, 6, 8, 10] P = arange(0, 1.01, 0.01) for ri in R: f = [Fi(p, ri, flujo, **kwargs) for p in P] self.plt.plot(P, f, "k") NTU = [0.2, 0.4, 0.6, 0.8, 1., 1.2, 1.4, 1.6, 1.8, 2.0, 2.5, 3.] for ntu in NTU: self.plt.plot([0, 1], [0, 1./ntu], "k", linestyle=":") # fraccionx=P[90]-P[80] # fracciony=f[90]-f[80] # try: # angle=arctan(fracciony/fraccionx)*360/2/pi # except ZeroDivisionError: # angle=90 # self.plt.ax.annotate( # "R=%0.1f" %ri, (P[90], f[90]), rotation=angle, size="medium", # horizontalalignment="left", verticalalignment="bottom") self.plt.draw()
chartHE = (Efectividad, TemperatureEfectividad, F, Phi) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) dialogo = Efectividad() dialogo.show() sys.exit(app.exec())