Source code for equipment.widget.twistedtapeAnnulli

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


from functools import partial
from math import pi, log, cos, atan

from tools.qt import QtCore, QtWidgets, translate

from equipment.widget.gui import ToolGui, CallableEntity
from lib.unidades import Length
from lib.utilities import refDoc
from UI.widgets import Entrada_con_unidades


__doi__ = {
    1:
        {"autor": "Coetzee, H., Liebenberg, L., Meyer, J.P.",
         "title": "Heat Transfer and Pressure Drop Characteristics of Angled "
                  "Spiraling Tape Inserts in a Heat Exchanger Annulus",
         "ref": "Heat Transfer Engineering 24(6) (2003) 29-39",
         "doi": "10.1080/714044412"},
    2:
        {"autor": "Gupte, N.S., Date, A.W.",
         "title": "Friction and Heat Transfer Characteristics of Helical "
                  "Turbulent Air Flow in Annuli",
         "ref": "J. Heat Transfer 111(2) (1989) 337-344",
         "doi": "10.1115/1.3250682"}}


# Friction factor correlations
[docs] @refDoc(__doi__, [1]) def f_twistedAnnulli_Coetzee(Re, Di, H, orientation=0): """Calculate friction factor for a annulus section for a double pipe with a twisted-tape insert using the Coetzee correlation (2003). Parameters ---------- Re : float Reynolds number, [-] Di : float Inner diameter of annuli, [m] H : float Tape pitch for twist of π radians (180º), [m] orientation : boolean Set flow orientation in the annulus with the curvature of tape 0(along flow), 1(against flow) Returns ------- f : float Friction factor, [-] """ y = H/Di if orientation: g1 = 0.3618*y**2 - 1.047*y + 0.9186 # Eq 13 g2 = -0.0669*y**2 + 0.1656*y - 0.2282 # Eq 14 else: g1 = 0.6283*y**2 - 1.6519*y + 1.1939 # Eq 15 g2 = -0.0797*y**2 + 0.1814*y - 0.2392 # Eq 16 # Eq 12 f = g1*Re**g2 return f
[docs] @refDoc(__doi__, [2]) def f_twistedAnnulli_Gupte(Re, Do, Di, H): """Calculate friction factor for a annulus section for a double pipe with a twisted-tape insert using the Gupte correlation (1989). Parameters ---------- Re : float Reynolds number, [-] Do : float Outer diameter of annuli, [m] Di : float Inner diameter of annuli, [m] H : float Tape pitch for twist of π radians (180º), [m] Returns ------- f : float Friction factor, [-] Examples -------- Selected point from Table 2 in [1]_ >>> st = f_twistedAnnulli_Gupte(1e4, 1, 0.61, 3) """ phi0 = 2*pi ri = Di/2 ro = Do/2 y = H/(ro-ri) r = ri/ro # Eq 9 tau = (r**0.686-r**2)/(r*(1-r**0.686)) # Eq 11 finf = 0.046/Re**0.2 # Eq 13 Dh_ = 2*phi0*(1-r**2)/(phi0*(1+r)+2*(1-r)) # Eq 15 K1 = ((1+r)*phi0 + 2*(1-r)) / ((1+r*tau)*phi0 + (1+tau)*(1-r)) # Eq 16 K2 = phi0*(1+r*tau) + (1-r)*(1+tau) # Eq 17 # Eq 18 K3 = (pi**2/(4*y**2*(1-r)**2))/(phi0*(1+r**2*tau)+(1-r**3)*(1+tau)/3) K5 = (K1**0.5/(2*y*(1-r)))*(2/finf)**0.5/Re**2 # Eq 20 K6 = (5.5+2.5*log(Re*(finf/2)**0.5/2))/K1**0.5 # Eq 21 K7 = 1/Dh_*(finf/2)**0.5*Re/K1**0.5 # Eq 22 # Eq 19 K4 = K5*(K6*(890*(1/tau-1)+30*K7*(r/tau**0.5+1)) + 5180*(1-1/tau**0.5) + 281.4*K7*(r-1)) # Eq 23 f = Dh_ * ((0.5*K1*(K2+K3)*finf + pi*Dh_**2*K4)/(phi0*(1-r**2))) return f
# Heat Transfer coefficient correlations
[docs] @refDoc(__doi__, [1]) def Nu_twistedAnnulli_Coetzee(Re, Pr, Di, H, mu=1, muW=1, orientation=0): """Calculate Nusselt number for a annulus section for a double pipe with a twisted-tape insert using the Coetzee correlation (2003). Parameters ---------- Re : float Reynolds number, [-] Pr : float Prandtl number, [-] Di : float Inner diameter of annuli, [m] H : float Tape pitch for twist of π radians (180º), [m] mu : float, optional Bulk flow temperature viscosity, [Pa·s] muW : float, optional Wall flow temperature viscosity, [Pa·s] orientation: boolean Set flow orientation in the annulus with the curvature of tape 0(along flow), 1(against flow) Returns ------- Nu : float Nusselt number, [-] """ y = H/Di if orientation: f1 = 2.256e-9*y**2 - 10.989e-9*y + 16.03e-9 # Eq 6 f2 = -21.04e-6*y**2 + 125.27e-6*y - 211.33e-6 # Eq 7 f3 = 0.449*y**2 - 2.329*y + 4.503 # Eq 8 else: f1 = -0.3969e-9*y**2 + 1.233e-9*y + 3.369e-9 # Eq 9 f2 = 4.866e-6*y**2 - 26.27e-6*y - 54.17e-6 # Eq 10 f3 = 0.449*y**2 - 1.969*y + 4.021 # Eq 11 # Eq 5 Nu = 0.0726*Re**0.8*Pr**0.333*(mu/muW)**0.14 * (f1*Re**2 + f2*Re + f3) return Nu
[docs] @refDoc(__doi__, [2]) def Nu_twistedAnnulli_Gupte(Re, Pr, Do, Di, H, boundary=0): """Calculate nusselt number for a annulus section for a double pipe with a twisted-tape insert using the Gupte correlation (1989). Parameters ---------- Re : float Reynolds number, [-] Pr : float Prandtl number, [-] Do : float Outer diameter of annuli, [m] Di : float Inner diameter of annuli, [m] H : float Tape pitch for twist of π radians (180º), [m] boundary : integer 0 - inner 1 - outer Returns ------- Nu : float Nusselt number, [-] """ phi0 = 2*pi ri = Di/2 ro = Do/2 r = ri/ro # Eq 9 tau = (r**0.686-r**2)/(r*(1-r**0.686)) # Eq 11 y = H/(ro-ri) finf = 0.046/Re**0.2 # Eq 13 Dh_ = 2*phi0*(1-r**2)/(phi0*(1+r)+2*(1-r)) # Eq 15 K1 = ((1+r)*phi0 + 2*(1-r)) / ((1+r*tau)*phi0 + (1+tau)*(1-r)) # Eq 16 K8 = pi*Dh_**2/(y*(1-r**2)*phi0*K1*finf*Re**2) # Eq 39 ro_ = Re/Dh_*(finf*K1/2)**0.5 # Eq 44 ri_ = Re*r*K1/Dh_*(finf*tau/2)**0.5 # Eq 45 alfai = atan(pi*ri/H) # Eq 48 alfao = atan(pi*ro/H) # Eq 49 PF = 9.24*((Pr/0.9)**0.75-1) # Eq 46 A = 25/Pr*(((1+5*Pr)/Pr) * (log(1+5*Pr)-1) + 1) # Eq 33 if boundary == 1: # Only outer wall heated K12 = 5250*Pr**0.731 - (137.5*Pr+A)*ro_ # Eq 43 # Eq 38a Stro = (K1*finf/2/cos(alfao))**0.5/0.9/(PF+(2*cos(alfao)/K1/finf)**0.5) # Eq 52 Nu = (Stro/(1+r)-K8*(450-30*ro_)) / (1/(1+r)-K8*K12*(2/K1*finf)**0.5) else: # Only inner wall heated K11 = ((137.5*Pr+A)*ri_ + 5250*Pr**0.731)/tau**0.5 # Eq 42 # Eq 38b Stri = (K1*tau**finf/2/cos(alfai))**0.5/0.9 / \ (PF+(2*cos(alfai)/tau/K1/finf)**0.5) # Eq 53 Nu = (Stri*r/(1+r) + 0.5*K8*K1*finf*(450+30*ri_)) / \ (r/(1+r) + K8*K11*(2/finf/K1)**0.5) return Nu*Re*Pr
[docs] class TwistedTapeAnnuli(CallableEntity): """Twisted-tape insert specially for annulli section of double-pipe section. Parameters ---------- H : float Tape pitch for twist of π radians (180º), [m] Do : float Outer diameter of annuli, [m] Di : float Inner diameter of annuli, [m] angled : boolean Set if twisted-tape is angled orientation: boolean Set flow orientation in the annulus with the curvature of tape 0(along flow), 1(against flow) """ TEXT_ORIENTACION = ( translate("equipment", "Along flow"), translate("equipment", "Against flow")) status = 0 msg = "" kw = { "H": 0, "Di": 0, "Do": 0, "angled": False, "orientation": 0} valueChanged = QtCore.pyqtSignal(object) inputChanged = QtCore.pyqtSignal(object) @property def isCalculable(self): """Check if all input are defined""" if not self.kw["H"]: self.msg = translate("equipment", "undefined tape pitch") self.status = 0 return False if not self.kw["Di"]: self.msg = translate("equipment", "undefined internal diameter") self.status = 0 return False if not self.kw["Do"]: self.msg = translate("equipment", "undefined external diameter") self.status = 0 return False self.msg = "" self.status = 1 return True
[docs] def calculo(self): """Definition of twisted tape inserts for annuli sections""" self.H = self.kw["H"] self.Di = self.kw["Di"] self.Do = self.kw["Do"] self.angled = self.kw["angled"] self.orientation = self.kw["orientation"] if self.angled and self.H/self.Di > 10: self.status = 3 self.msg = translate( "equipment", "Coetzee correlation out of bound, using Gupte instead") self.valueChanged.emit(self)
[docs] def Nu(self, Re, Pr, mu, muW, boundary=0): """Calculate nusselt number""" if self.angled and self.H/self.Di > 10: Nu = Nu_twistedAnnulli_Coetzee( Re, Pr, self.Di, self.H, mu, muW, self.orientation) else: Nu = Nu_twistedAnnulli_Gupte(Re, Pr, self.Do, self.Di, self.H, boundary) return Nu
[docs] def f(self, Re): """Calculate friction factor""" if self.angled and self.H/self.Di > 10: f = f_twistedAnnulli_Coetzee(Re, self.Di, self.H, self.orientation) else: f = f_twistedAnnulli_Gupte(Re, self.Do, self.Di, self.H) return f
[docs] class UI_TwistedTapeAnnuli(ToolGui): """Twisted-tape insert dialog""" title = translate("equipment", "Use twisted tape insert in annuli section")
[docs] def loadUI(self): """Add widget""" self.Entity = TwistedTapeAnnuli() lyt = self.wdg.layout() label = QtWidgets.QLabel(self.tr("Tape pitch, H")) label.setToolTip(self.tr("Tape pitch for twist of π radians (180º)")) lyt.addWidget(label, 2, 1) self.H = Entrada_con_unidades(Length) self.H.valueChanged.connect(partial(self.changeParams, "H")) lyt.addWidget(self.H, 2, 2) label = QtWidgets.QLabel("Di") label.setToolTip(self.tr("Internal diameter of annuli section")) lyt.addWidget(label, 3, 1) self.Di = Entrada_con_unidades(Length, "PipeDiameter") self.Di.valueChanged.connect(partial(self.changeParams, "Di")) lyt.addWidget(self.Di, 3, 2) label = QtWidgets.QLabel("Do") label.setToolTip(self.tr("External diameter of annuli section")) lyt.addWidget(label, 4, 1) self.Do = Entrada_con_unidades(Length, "PipeDiameter") self.Do.valueChanged.connect(partial(self.changeParams, "Do")) lyt.addWidget(self.Do, 4, 2) self.angled = QtWidgets.QCheckBox(self.tr("Angled twisted-tape")) self.angled.toggled.connect(self.setEnableOrientation) lyt.addWidget(self.angled, 5, 1, 1, 2) lytH = QtWidgets.QHBoxLayout() self.labelOrientation = QtWidgets.QLabel(self.tr( "Direction of flow relative to the tape curvature")) lytH.addWidget(self.labelOrientation) self.orientation = QtWidgets.QComboBox() for method in TwistedTapeAnnuli.TEXT_ORIENTACION: self.orientation.addItem(method) self.orientation.currentIndexChanged.connect( partial(self.changeParams, "orientation")) lytH.addWidget(self.orientation) lyt.addLayout(lytH, 7, 1, 1, 2) self.Entity.valueChanged.connect(self.valueChanged.emit) self.Entity.inputChanged.connect(self.populate)
[docs] def setEnabled(self, boolean): """Add logic to parent setEnabled for orientation option""" ToolGui.setEnabled(self, boolean) self.setEnableOrientation(boolean and self.angled.isChecked())
[docs] def setEnableOrientation(self, boolean): """Change Enable/Disable state for orientation of twisted tape""" self.labelOrientation.setEnabled(boolean) self.orientation.setEnabled(boolean) self.changeParams("angled", boolean)
[docs] class Dialog(QtWidgets.QDialog): """Component list config dialog"""
[docs] def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle(self.tr("Twisted-tape insert")) layout = QtWidgets.QVBoxLayout(self) self.datos = UI_TwistedTapeAnnuli() layout.addWidget(self.datos) 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)
if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) Dialog = Dialog() Dialog.show() sys.exit(app.exec())