#!/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())