#!/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 atan, log, pi
from scipy.optimize import newton
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": "Naphon, P., Nuchjapo, M., Kurujareon, J.",
"title": "Tube side heat transfer coefficient and friction factor "
"characteristics of horizontal tubes with helical rib",
"ref": "Energy Conv. Management 47(18-19) (2006) 3031-3044",
"doi": "10.1016/j.enconman.2006.03.023"},
2:
{"autor": "Vicente, P.G., García, A., Viedma, A.",
"title": "Experimental investigation on heat transfer and frictional "
"characteristics of spirally corrugated tubes in turbulent "
"flow at different Prandtl numbers",
"ref": "Int. J. Heat Mass Transfer 47(4) (2004) 671-681",
"doi": "10.1016/j.ijheatmasstransfer.2003.08.005"},
3:
{"autor": "Vicente, P.G., García, A., Viedma, A.",
"title": "Mixed convection heat transfer and isothermal pressure "
"drop in corruageted tubes for laminar and transition flow",
"ref": "Int. Comm. Heat Mass Transfer 31(5) (2004) 651-662",
"doi": "10.1016/S0735-1933(04)00052-1"},
4:
{"autor": "Sethumadhavan, R., Raja Rao, M.",
"title": "Turbulent Flow Friction and Heat Transfer Characteristics "
"of Single and Multistart Spirally Enghanced Tubes",
"ref": "J. Heat Transfer 108(1) (1986) 55-61",
"doi": "10.1115/1.3246905"},
5:
{"autor": "Dong, Y., Huixiong, L., Tingkuan, C.",
"title": "Pressure drop, heat transfer and performance of "
"single-phase turbulent flow in spirally corrugated tubes",
"ref": "Exp. Thermal Fluid Sci. 24(3-4) (2001) 131-138",
"doi": "10.1016/S0894-1777(01)00047-4"},
6:
{"autor": "Srinivasan, V., Christensen, R.N.",
"title": "Experimental Investigation of Heat Transfer and Pressure "
"Drop Characteristics of Flow Through Spirally Fluted Tubes",
"ref": "Exp. Thermal Fluid Sci. 5(6) (1992) 820-827",
"doi": "10.1016/0894-1777(92)90126-P"},
# 7:
# {"autor": "",
# "title": "",
# "ref": "",
# "doi": ""},
}
# Friction factor correlations
[docs]
@refDoc(__doi__, [2, 3])
def f_corrugated_Vicente(Re, Di, p, h):
"""Calculate friction factor for a corrugated tube using the Vicente et al.
correlation (2004).
Parameters
----------
Re : float
Reynolds number, [-]
Di : float
Internal diameter of tube, [m]
p : float
Helical pitch for twist of 2π radians (360º), [m]
h : float
Roughness height, [m]
Returns
-------
f : float
Friction factor, [-]
"""
# Tube severity factor
phi = h**2/p/Di
if Re > 2000:
# Turbulent flow, Eq 2
f = 1.53 * phi**0.46 / Re**0.16
else:
# Laminar flow, Eq 3 in [3]_
f = 29.8 * phi**0.11 / Re**0.97
return f
[docs]
@refDoc(__doi__, [4])
def f_corrugated_Sethumadhavan(Re, Di, P, h):
"""Calculate friction factor for a corrugated pipe using the
Sethumadhavan-Raja Rao correlation (1986).
Parameters
----------
Re : float
Reynolds number, [-]
D : float
Internal diameter of tube, [m]
P : float
helical pitch for twist of 2π radians (360º), [m]
h : float
Roughness height, [m]
Returns
-------
f : float
Friction factor, [-]
"""
if Re < 5000:
raise NotImplementedError("Input out of bound")
Deq = Di-h
# Eq 11
def f_res(f):
"""Iterative solution of intrinsic equation"""
R = (2/f)**0.5 + 2.5*log(2*h/Deq) + 3.75
h_ = h/Deq * Re * (f/2)**0.5
return R*h**2/(P*Deq)**0.33 - 0.40*h_**0.164
fo = f_corrugated_Vicente(Re, Di, P, h)
f = newton(f_res, fo)
if isinstance(f, complex):
raise ValueError("Solution don't converge")
return f
[docs]
@refDoc(__doi__, [5])
def f_corrugated_Dong(Re, Di, P, h):
"""Calculate friction factor for a corrugated pipe using the Dong et al.
correlation (2001).
Parameters
----------
Re : float
Reynolds number, [-]
D : float
Internal diameter of tube, [m]
P : float
helical pitch for twist of 2π radians (360º), [m]
h : float
Roughness height, [m]
Returns
-------
f : float
Friction factor, [-]
"""
if Re < 6000:
raise NotImplementedError("Input out of bound")
# Helix angle
alpha = atan(P/pi/Di)*180/pi
# Tube severity factor
phi = h**2/P/Di
# Eq 13
def f_res(f):
"""Iterative solution of intrinsic equation"""
R = (2/f)**0.5 + 2.5*log(2*h/Di) + 3.75
h_ = h/Di * Re * (f/2)**0.5
return R * phi**0.317 * (alpha/50)**0.16 - 0.455*h_**0.169
fo = f_corrugated_Vicente(Re, Di, P, h)
f = newton(f_res, fo)
if isinstance(f, complex):
raise ValueError("Solution don't converge")
return f
# Heat Transfer coefficient correlations
[docs]
@refDoc(__doi__, [2, 3])
def Nu_corrugated_Vicente(Re, Pr, Di, p, h):
"""Calculate friction factor for a corrugated tube using the Vicente et al.
correlation (2004).
Parameters
----------
Re : float
Reynolds number, [-]
Pr : float
Prandtl number, [-]
Di : float
Internal diameter of tube, [m]
p : float
Helical pitch for twist of 2π radians (360º), [m]
h : float
Roughness height, [m]
Returns
-------
Nu : float
Nusselt number, [-]
"""
# Tube severity factor
phi = h**2/p/Di
if Re > 2000:
# Turbulent flow, Eq 9
Nu = 0.374 * phi**0.25 * (Re-1500)**0.74 * Pr**0.44
else:
# Laminar flow, for simplicity use the constant infinite value to avoid
# Rayleigh input parameters
Nu = 4.36
return Nu
[docs]
@refDoc(__doi__, [4])
def Nu_corrugated_Sethumadhavan(Re, Pr, Di, P, h):
"""Calculate Nusselt number for a corrugated pipe using the
Sethumadhavan-Raja Rao correlation (1986).
Parameters
----------
Re : float
Reynolds number, [-]
Pr : float
Prandtl number, [-]
Di : float
Internal diameter of tube, [m]
p : float
Helical pitch for twist of 2π radians (360º), [m]
h : float
Roughness height, [m]
Returns
-------
Nu : float
Nusselt number, [-]
"""
if Re < 5000:
raise NotImplementedError("Input out of bound")
Deq = Di-h
f = f_corrugated_Vicente(Re, Di, P, h)
h_ = h/Deq * Re * (f/2)**0.5
R = (2/f)**0.5 + 2.5*log(2*h/Deq) + 3.75
# Eq 15
G = 8.6 * h_**0.13 * Pr**0.55
# Eq 7
St = 1/((((G-R)*(f/2)**0.5)+1)*2/f)
return St*Re*Pr
[docs]
@refDoc(__doi__, [5])
def Nu_corrugated_Dong(Re, Pr, Di, P, h):
"""Calculate nusselt number for a corrugated pipe using the Dong et al.
correlation (2001).
Parameters
----------
Re : float
Reynolds number, [-]
Pr : float
Prandtl number, [-]
D : float
Internal diameter of tube, [m]
P : float
helical pitch for twist of 2π radians (360º), [m]
h : float
Roughness height, [m]
Returns
-------
Nu : float
Nusselt number, [-]
"""
if Re < 6000:
raise NotImplementedError("Input out of bound")
# Helix angle
alpha = atan(P/pi/Di)*180/pi
Deq = Di-h
f = f_corrugated_Vicente(Re, Di, P, h)
h_ = h/Deq * Re * (f/2)**0.5
R = (2/f)**0.5 + 2.5*log(2*h/Deq) + 3.75
# Eq 16
G = 7.33*h_**0.175 / (alpha/50)**0.16 * Pr**0.548
# Eq 7
St = 1/((((G-R)*(f/2)**0.5)+1)*2/f)
return St*Re*Pr
# Fluted tubes
[docs]
@refDoc(__doi__, [1])
def f_fluted_Srinivasan(Re, Di, p, h, N):
"""Calculate friction factor for a spirally flutud tube using the
Srinivasan correlation (1992).
Parameters
----------
Re : float
Reynolds number, [-]
Di : float
Internal diameter of tube, [m]
p : float
Helical rib pitch for twist of 2π radians (360º), [m]
h : float
Flute depth, [m]
N : integer
Number of flute starts, [-]
Returns
-------
f : float
Friction factor, [-]
"""
# Helix angle
alpha = atan(p/pi/Di/N)*180/pi
tita = alpha/90
# Eq 2
f = 12.745 * Re**(-0.474-0.209*p/Di+0.685*tita) * \
(h/Di)**(1.292+0.031*p/Di) * p/Di**(9.908+0.331e-5*Re-12.074*tita)
return f
[docs]
@refDoc(__doi__, [6])
def Nu_fluted_Srinivasan(Re, Pr, Di, p, h, N):
"""Calculate Nusselt number for a tube with helical rib using the Naphon
correlation (1992).
Parameters
----------
Re : float
Reynolds number, [-]
Pr : float
Prandtl number, [-]
Di : float
Internal diameter of tube, [m]
p : float
Helical rib pitch for twist of 2π radians (360º), [m]
h : float
Helical rib depth, [m]
N : integer
Number of flute starts, [-]
Returns
-------
Nu : float
Nusselt number, [-]
"""
# Helix angle
alpha = atan(p/pi/Di/N)*180/pi
tita = alpha/90
if Re < 5000:
# Eq 4, laminar flow
Nu = 0.014*Re**0.847*Pr**0.4/(h/Di)**0.067/(p/Di)**0.293/tita**0.705
else:
# Eq 5, turbulent flow
Nu = 0.064*Re**0.773*Pr**0.4/(h/Di)**0.242/(p/Di)**0.108/tita**0.599
return Nu
# Rib correlation
[docs]
@refDoc(__doi__, [1])
def f_rib_Naphon(Re, Di, p, h):
"""Calculate friction factor for a tube with helical rib using the Naphon
correlation (2006).
Parameters
----------
Re : float
Reynolds number, [-]
Di : float
Internal diameter of tube, [m]
p : float
Helical rib pitch for twist of 2π radians (360º), [m]
h : float
Helical rib depth, [m]
Returns
-------
f : float
Friction factor, [-]
"""
# Eq 11
f = 7.85 / Re**0.21 * (h/Di)**1.68 / (p/Di)**0.54
return f
[docs]
@refDoc(__doi__, [1])
def Nu_rib_Naphon(Re, Pr, Di, p, h):
"""Calculate Nusselt number for a tube with helical rib using the Naphon
correlation (2006).
Parameters
----------
Re : float
Reynolds number, [-]
Pr : float
Prandtl number, [-]
Di : float
Internal diameter of tube, [m]
p : float
Helical rib pitch for twist of 2π radians (360º), [m]
h : float
Helical rib depth, [m]
Returns
-------
Nu : float
Nusselt number, [-]
"""
# Eq 8
Nu = 44.26 * (Re-1500)**0.27 / Pr**0.26 * (h/Di)**0.89 / (p/Di)**0.96
return Nu
[docs]
class Rib(CallableEntity):
"""Helical rip tube
Parameters
----------
p : float
Helical rib pitch for twist of 2π radians (360º), [m]
h : float
Helical rib depth, [m]
"""
TEXT_FRICTION = (
"Vicente (2004)",
"Sethumadhavan-Raja Rao (1986)",
"Dong (2001)")
TEXT_HEAT = (
"Vicente (2004)",
"Sethumadhavan-Raja Rao (1986)",
"Dong (2001)")
status = 0
msg = ""
kw = {
"p": 0,
"h": 0,
"methodCorrugatedFriction": 0,
"methodCorrugatedHeat": 0,
"isRib": False,
"isFluted": False,
"N": 1}
valueChanged = QtCore.pyqtSignal(object)
inputChanged = QtCore.pyqtSignal(object)
@property
def isCalculable(self):
"""Check if all input are defined"""
if not self.kw["p"]:
self.msg = translate("equipment", "undefined rib pitch")
self.status = 0
return False
if not self.kw["h"]:
self.msg = translate("equipment", "undefined rib depth")
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.p = self.kw["p"]
self.h = self.kw["h"]
self.valueChanged.emit(self)
[docs]
def Nu(self, Re, Pr, Di):
"""Calculate nusselt number"""
msg = ""
if self.kw["isRib"]:
Nu = Nu_rib_Naphon(Re, Pr, Di, self.p, self.h)
return Nu
if self.kw["isFluted"]:
Nu = Nu_fluted_Srinivasan(Re, Pr, Di, self.p, self.h, self.kw["N"])
return Nu
if self.kw["methodCorrugatedHeat"] == 1:
# "Sethumadhavan-Raja Rao (1986)",
try:
Nu = Nu_corrugated_Sethumadhavan(Re, Pr, Di, self.p, self.h)
except RuntimeError:
Nu = Nu_corrugated_Vicente(Re, Pr, Di, self.p, self.h)
msg = "Sethumadhavan method don't converge, using Vicente method instead"
elif self.kw["methodCorrugatedHeat"] == 2:
# "Dong (2001)")
Nu = Nu_corrugated_Dong(Re, Pr, Di, self.p, self.h)
else:
# "Vicente (2004)",
Nu = Nu_corrugated_Vicente(Re, Pr, Di, self.p, self.h)
if msg:
self.status = 3
self.msg = translate("equipment", msg)
self.inputChanged.emit(self)
return Nu
[docs]
def f(self, Re, Di):
"""Calculate friction factor"""
msg = ""
if self.kw["isRib"]:
f = f_rib_Naphon(Re, Di, self.p, self.h)
return f
if self.kw["isFluted"]:
f = f_fluted_Srinivasan(Re, Di, self.p, self.h, self.kw["N"])
return f
if self.kw["methodCorrugatedFriction"] == 1:
# "Sethumadhavan-Raja Rao (1986)",
try:
f = f_corrugated_Sethumadhavan(Re, Di, self.p, self.h)
except RuntimeError:
f = f_corrugated_Vicente(Re, Di, self.p, self.h)
msg = "Sethumadhavan method don't converge, using Vicente method instead"
elif self.kw["methodCorrugatedFriction"] == 2:
# "Dong (2001)")
f = f_corrugated_Dong(Re, Di, self.p, self.h)
else:
# "Vicente (2004)",
f = f_corrugated_Vicente(Re, Di, self.p, self.h)
if msg:
self.status = 3
self.msg = translate("equipment", msg)
self.inputChanged.emit(self)
return f
[docs]
class UI_Rib(ToolGui):
"""Helical rib dialog"""
title = translate("equipment", "Use helical rib in tube")
[docs]
def loadUI(self):
"""Add widget"""
self.Entity = Rib()
lyt = self.wdg.layout()
self.corrugated = QtWidgets.QRadioButton(self.tr("Corrugated tube"))
self.corrugated.setChecked(True)
lyt.addWidget(self.corrugated, 1, 1, 1, 3)
groupMethods = QtWidgets.QWidget()
lytM = QtWidgets.QGridLayout(groupMethods)
lytM.addItem(QtWidgets.QSpacerItem(
20, 20, QtWidgets.QSizePolicy.Policy.Fixed,
QtWidgets.QSizePolicy.Policy.Fixed), 1, 0, 2, 1)
lytM.addWidget(QtWidgets.QLabel(
self.tr("Friction factor method")), 1, 1)
self.methodCorrugatedFriction = QtWidgets.QComboBox()
for method in Rib.TEXT_FRICTION:
self.methodCorrugatedFriction.addItem(method)
self.methodCorrugatedFriction.currentIndexChanged.connect(
partial(self.changeParams, "methodCorrugatedFriction"))
lytM.addWidget(self.methodCorrugatedFriction, 1, 2)
lytM.addWidget(QtWidgets.QLabel(
self.tr("Heat transfer method")), 2, 1)
self.methodCorrugatedHeat = QtWidgets.QComboBox()
for method in Rib.TEXT_HEAT:
self.methodCorrugatedHeat.addItem(method)
self.methodCorrugatedHeat.currentIndexChanged.connect(
partial(self.changeParams, "methodCorrugatedHeat"))
lytM.addWidget(self.methodCorrugatedHeat, 2, 2)
lyt.addWidget(groupMethods, 2, 1, 1, 2)
self.corrugated.toggled.connect(groupMethods.setEnabled)
self.rib = QtWidgets.QRadioButton(self.tr("Rib tube"))
self.rib.toggled.connect(partial(self.changeParams, "isRib"))
lyt.addWidget(self.rib, 4, 1, 1, 3)
self.fluted = QtWidgets.QRadioButton(self.tr("Fluted tube"))
self.fluted.toggled.connect(self.setEnableFluted)
lyt.addWidget(self.fluted, 5, 1, 1, 3)
lyt.addItem(QtWidgets.QSpacerItem(
10, 10, QtWidgets.QSizePolicy.Policy.Fixed,
QtWidgets.QSizePolicy.Policy.Fixed), 6, 1)
label = QtWidgets.QLabel(self.tr("Rib pitch"))
label.setToolTip(self.tr("Pitch for twist of 2π radians (360º)"))
lyt.addWidget(label, 8, 1)
self.p = Entrada_con_unidades(Length)
self.p.valueChanged.connect(partial(self.changeParams, "p"))
lyt.addWidget(self.p, 8, 2)
lyt.addWidget(QtWidgets.QLabel("Rib depth"), 9, 1)
self.h = Entrada_con_unidades(Length, "Thickness")
self.h.valueChanged.connect(partial(self.changeParams, "h"))
lyt.addWidget(self.h, 9, 2)
self.lblN = QtWidgets.QLabel(self.tr("Rib count"))
lyt.addWidget(self.lblN, 10, 1)
self.N = Entrada_con_unidades(int, spinbox=True)
self.N.valueChanged.connect(partial(self.changeParams, "N"))
lyt.addWidget(self.N, 10, 2)
self.Entity.valueChanged.connect(self.valueChanged.emit)
self.Entity.inputChanged.connect(self.populate)
self.lblN.setVisible(False)
self.N.setVisible(False)
[docs]
def setEnableFluted(self, boolean):
self.lblN.setVisible(boolean)
self.N.setVisible(boolean)
self.changeParams("isFluted", 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_Rib()
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())