#!/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 numpy import logspace
from lib.unidades import Dimensionless
from tools.qt import translate
from equipment.parents import equipment
def h_shellside_turbulent_Bell_Delaware(**kw):
"""Coeficiente de transferencia de calor por calor sensible en el parte de la carcasa en regimen turbulento
Serth - Process Heat Transfer - Principles and applications Cap. 6
kw include
DeTube (d) - Tube outside diameter
tipo - Tube layout pattern
Ds - Shell inside diameter
Dotl - Tube bank outer tube limit diameter
Ltl - Effective tube length
Bc - Baffle cut as a percent of D
Lbc - Central baffle spacing
Nss - Number of sealing strips per side
"""
# Bundle-to-shell clearance
Lbb = 12+0.005*kw["Ds"]
# Bundle diameter
Dotl = kw["Ds"] - Lbb
fi = 1
PtD = kw["pitch"]/kw["DeTube"]
mo = kw["entradaCarcasa"].caudalmasico
if kw["distribucionTube"] == 2:
Ptef = kw["pitch"]/2**0.5
else:
Ptef = kw["pitch"]
if kw["distribucionTube"] < 3:
tita_tp = unidades.Angle([30, 45, 60, 90][kw["distribucionTube"]], "deg")
Pt_ = kw["pitch"]*cos(tita_tp)
else:
Pt_ = kw["pitch"]
Nc = kw["Ds"]*(1-2*kw["baffleCut"])/Pt_
Ncw = 0.8*kw["baffleCut"]*kw["Ds"]/Pt_
Dotl = kw["Ds"]-2*kw["clearanceShellBundle"]
Sm = kw["baffleSpacing"]*(kw["Ds"]-Dotl+(Dotl-kw["DeTube"])/Ptef*(kw["pitch"]-kw["DeTube"]))
G = mo/Sm
Re = kw["DeTube"]*G/kw["entradaCarcasa"].Liquido.mu
Pr = kw["entradaCarcasa"].Liquido.Pr
rho = kw["entradaCarcasa"].Liquido.rho
cp = kw["entradaCarcasa"].Liquido.cp
Dctl = Dotl-kw["DeTube"]
tita_ctl = 2*arccos(kw["Ds"]*(1-2*kw["baffleCut"])/Dctl)
Fc = 1+1./pi*(sin(tita_ctl)-tita_ctl)
Fw = 1./2/pi*(tita_ctl-sin(tita_ctl))
Stb = pi/8*((kw["DeTube"]+2*kw["clearanceTubeBaffle"])**2-kw["DeTube"]**2)*kw["NTube"]*(1+Fc)
tita_ds = 2*arccos(1-2*kw["baffleCut"])
Ssb = kw["Ds"]*kw["clearanceShellBaffle"]*(pi-0.5*tita_ds)
Sb = kw["baffleSpacing"]*(kw["Ds"]-Dotl)
Sw = 1./8*kw["Ds"]**2*(tita_ds-sin(tita_ds))-1./4*kw["NTube"]*Fw*pi*kw["DeTube"]**2
Dw = 4*Sw/(pi*kw["DeTube"]*kw["NTube"]*0.5*(1-Fc)+kw["Ds"]*tita_ds)
# Jc: Correction factor for baffle configuration
Jc = 0.55+0.72*Fc
# Jl: Correction factor for baffle leakage effects, including both
# tube-to-baffle and baffle-to-shell leakages.
rs = Ssb/(Ssb+Stb)
rl = (Ssb+Stb)/Sm
Jl = 0.44*(1-rs)+(1-0.44*(1-rs))*exp(-2.2*rl)
Rl = exp(-1.33*(1+rs)*rl**(0.8-0.15*(1+rs)))
# Jb: Correction factor for bundle and pass partition bypass stream
rss = kw["sealingStrips"]/Nc
if rss < 0.5:
if Re < 100:
Cj = 1.35
Cr = 4.5
else:
Cj = 1.25
Cr = 3.7
Jb = exp(-Cj*Sb/Sm*(1-(2*rss)**(1./3)))
Rb = exp(-Cr*Sb/Sm*(1-(2*rss)**(1./3)))
else:
Jb = 1.
Rb = 1.
# Js: Correction factor for larger baffle spacing at the inlet and outlet
# sections compared to the central baffle spacing.
if Re < 100:
n1 = 1./3
n2 = 1.
else:
n1 = 0.6
n2 = 0.2
nb = kw["LTube"]/kw["baffleSpacing"]
if kw["baffleSpacingIn"] > kw["baffleSpacing"]:
nb += 1
if kw["baffleSpacingOut"] > kw["baffleSpacing"]:
nb += 1
Js = (nb-1+(kw["baffleSpacingIn"]/kw["baffleSpacing"])**(1-n1)+(kw["baffleSpacingOut"]/kw["baffleSpacing"])**(1-n1))/(nb-1+(kw["baffleSpacingIn"]/kw["baffleSpacing"])+kw["baffleSpacingOut"]/kw["baffleSpacing"])
Rs = 0.5*((kw["baffleSpacing"]/kw["baffleSpacingIn"])**(2-n2)+(kw["baffleSpacing"]/kw["baffleSpacingOut"])**(2-n2))
# Jr: Correction factor for any adverse temperature gradient in laminar
# flow. Only applies for Re < 100
Nct = (nb+1)*(Nc+Ncw)
if Re <= 20:
Jr = (10/Nct)**0.18
elif Re >= 100:
Jr = 1.
else: # Interpolacion entre los valores de arriba
Jr = 0.853379+0.0014662*Re
j = jFactor(Re, PtD, kw["distribucionTube"])
f = fFactor(Re, PtD, kw["distribucionTube"])
hid = j*cp*G*fi/Pr**(2./3)
h = unidades.HeatTransfCoef(hid*Jc*Jl*Jb*Jr*Js)
DPideal = 2*f*Nc*G**2/g/rho/fi
DPc = (nb-1)*DPideal*Rl*Rb
if Re > 100:
DPwideal = (2+0.6*Ncw)*mo**2/2/g/rho/Sm/Sw
else:
DPwideal = 26*nu*mo/g/(Sm*Sw)**0.5*(Ncw/PtD+kw["baffleCut"]*kw["Ds"]/Dw**2)+mo**2/g/rho/Sm/Sw
DPw = nb*DPwideal*Rl
# Eq 6.15
DPe = 2*DPideal*(1+Ncw/Nc)*Rb*Rs
mon = mo/kw["parallel"]
DPn = 0
for D in kw["nozzleInShellsideDiameter"], kw["nozzleOutShellsideDiameter"]:
Ren = D*mon/kw["entradaCarcasa"].Liquido.mu
Sn = pi/4*D**2
if Ren > 100:
DPn += 2e-13*kw["serie"]*mon**2/Sn
else:
DPn += 4e-13*kw["serie"]*mon**2/Sn
DP = unidades.DeltaP(DPc+DPw+DPe+DPn)
return h, DP
def jFactor(Re, PtD, tubeConf):
"""
Parameters
----------
Re : float
Reynolds number
PtD : float
Ratio between tube pitch and tube OD
tubeConf : str
Code with tube bundle configuration, square|triangular|rotSquare
Return
------
j : float
adimensional heat transfer coefficient
"""
# Table 6.1
if tubeConf == "rotSquare":
a3, a4 = 1.93, 0.5
if Re < 10:
a1, a2 = 1.55, -0.667
elif Re < 100:
a1, a2 = 1.498, -0.656
elif Re < 1000:
a1, a2 = 0.73, -0.500
else:
a1, a2 = 0.37, -0.396
elif tubeConf == "square":
a3, a4 = 1.187, 0.37
if Re < 10:
a1, a2 = 0.97, -0.667
elif Re < 100:
a1, a2 = 0.9, -0.631
elif Re < 1000:
a1, a2 = 0.408, -0.46
elif Re < 10000:
a1, a2 = 0.107, -0.266
else:
a1, a2 = 0.37, -0.395
else:
a3, a4 = 1.45, 0.519
if Re < 10:
a1, a2 = 1.4, -0.667
elif Re < 100:
a1, a2 = 1.36, -0.657
elif Re < 1000:
a1, a2 = 0.593, -0.477
else:
a1, a2 = 0.321, -0.388
a = a3/(1+0.14*Re**a4) # Eq 6.3
j = a1*(1.33/PtD)**a*Re**a2 # Eq 6.1
return Dimensionless(j)
def fFactor(Re, PtD, tubeConf):
"""
Parameters
----------
Re : float
Reynolds number
PtD : float
Ratio between tube pitch and tube OD
tubeConf : integer
integer with index of tube bundle configuration, 30, 45, 60, 90
Return
------
f : float
friction factor coefficient
"""
# Table 6.1
if tubeConf == "rotSquare":
b3, b4 = 6.59, 0.52
if Re < 10:
b1, b2 = 32, -1
elif Re < 100:
b1, b2 = 26.2, -0.913
elif Re < 1000:
b1, b2 = 3.5, -0.476
elif Re < 10000:
b1, b2 = 0.333, -0.136
else:
b1, b2 = 0.303, -0.126
elif tubeConf == "square":
b3, b4 = 6.3, 0.378
if Re < 10:
b1, b2 = 35, -1
elif Re < 100:
b1, b2 = 32.1, -0.963
elif Re < 1000:
b1, b2 = 6.09, -0.602
elif Re < 10000:
b1, b2 = 0.0815, 0.022
else:
b1, b2 = 0.391, -0.148
else:
b3, b4 = 7, 0.5
if Re < 10:
b1, b2 = 48, -1
elif Re < 100:
b1, b2 = 45.1, -0.973
elif Re < 1000:
b1, b2 = 4.570, -0.476
elif Re < 10000:
b1, b2 = 0.486, -0.152
else:
b1, b2 = 0.372, -0.123
b = b3/(1+0.14*Re**b4) # Eq 6.4
f = b1*(1.33/PtD)**b*Re**b2 # Eq 6.2
return Dimensionless(f)
[docs]
class Shell_Tube(equipment):
"""Class that defines a shell and tubes heat exchanger
Parameters
----------
entrada : Corriente
Input stream to equipment
Parámetros:
entrada: Array con dos Instancia de clase corriente que define las corrientes que fluye por el equipo, en el orden [tubo, carcasa]
entradaTubo: Instancia de clase corriente que define la corriente que pasa por los tubos
entradaCarcasa: Instancia de calse corriente que define la corriente que pasa por la carcasa
Standard:
class_: Clase del standard TEMA:
0 - Clase R
1 - Clase B
2 - Clase C
frontHead: Tipo de cabezal inicial
0 - Channel & Removable Cover
1 - Bonnet
2 - Removable Bundle
3 - Special High Pressure Closure
4 - Channel with Tubesheet & Removable Cover
shell: Tipo de carcasa
0 - One Pass
1 - Two Pass
2 - Split Flow
3 - Double Split Flow
4 - Divided Flow
5 - Kettle Reboiler
6 - Cross Flow
rearHead: Tipo de cabezal final
0 - Fixed Tubesheet (A head)
1 - Fixed Tubesheet (B head)
2 - Fixed Tubesheet (N head)
3 - Outside Packed Flt Head
4 - Flt Head with Backing Dev
5 - Pull Throught Flt Heat
6 - U-Tube Bundle
7 - Exit Sealed Flt Tubesheet
orientation: Orientaction del cambiador
0 - Horizontal
1 - Vertical
Métodos:
tubesideLaminar: Método de cálculo de h en el lado del tubo en regimen laminar
0 - Eubank-Proctor
1 - VDI mean Nusselt
2 - Hausen
3 - Sieder-Tate
tubesideTurbulent: Método de cálculo de h en el lado del tubo en regimen turbulento
0 - Sieder-Tate
1 - Colburn
2 - Dittus-Boelter
3 - ESDU
4 - Gnielinski
5 - VDI mean Nusselt
shellsideSensible: Método de cálculo de h en el lado de la carcasa
0 - Stream analysis
1 - Bell-Delaware
2 - Kern
Tubo:
NTubes: Número de tubos
NPases: Número de pasos de los tubos por la carcasa
LTube: Lóngitud de tubos
DeTube: Diametro externo
wTube: Espesor de la tubería
rTube: rugosidad interna de los tubos
kTube: Conductividad térmica
distribucionTube: Distribucion de tubos
0 - Triangular, 30º
1 - Diamante, 45º
2 - Rotated Triangular, 60º
3 - Square, 90º
pitch: Espacio entre tuberias
finned: boolean que indica que la tubería tiene alerones
0 - tubería lisa
1 - tubería con alerones
Nfin: numero de aletas por metro de tubería
heightFin:
foulingTube: resistencia por depositos en la parte del tubo
Carcasa:
parallel: Número de intercambiadores en paralelo
serie: Número de intercambiadores en serie
Ds: Diematro de la carcasa
foulingShell: resistencia por depositos en la parte de la carcasa
Baffle:
typeBaffle: Tipo de baffle
0 - Single segmental
1 - Double segmental
2 - Triple segmental
3 - No tubes in window
4 - Disk & donut
5 - Rod
baffleSpacingIn: Espacio de separación anterior al primer bafle
baffleSpacing: Espacio de separación entre baffles
baffleSpacingOut: Espacio de separación posterior al último bafle
baffleThickness: Espesor de los baffles
BaffleOrientation: Orientación de los baffles
0 - Horizontal
1 - Vertical
baffleCut: Porcentaje de corte de los baffles
baffleCutBase: Base de cálculo del porcentaje de corte
0 - Diámetro
1 - Área
Clearances:
clearanceTubeBaffle
clearanceShellBaffle
clearanceShellBundle
sealingStrips
Coste:
tipo: tipo de cambiador
0 - Fired head
1 - Kettle reboiler
2 - U-tubes
material:
0 - Carbon Steel
1 - Stainless steel 316
2 - Stainless steel 304
3 - Stainless steel 347
4 - Nickel 200
5 - Monel 400
6 - Inconel 600
7 - Incoloy 825
8 - Titanium
9 - Hastelloy
P_dis: Presión de diseño, si no se especifica se usará la máxima presión del las corrientes del proceso
"""
title = translate("equipment", "Shell and Tube Heat Exchanger")
help = ""
kwargs = {
"entrada": [],
"entradaTubo": None,
"entradaCarcasa": None,
"class_": 0,
"frontHead": 0,
"shell": 0,
"rearHead": 0,
"orientation": 0,
"tubesideLaminar": 0,
"tubesideTurbulent": 0,
"shellsideSensible": 0,
"NTube": 0,
"NPases": 0,
"LTube": 0.0,
"DeTube": 0.0,
"wTube": 0.0,
"rTube": 0.0,
"kTube": 0.0,
"distribucionTube": 0,
"pitch": 0,
"finned": 0,
"Nfin": 0,
"heightFin": 0.0,
"foulingTube": 0.0,
"parallel": 0,
"serie": 0,
"Ds": 0.0,
"foulingShell": 0.0,
"baffleType": 0,
"baffleSpacingIn": 0.0,
"baffleSpacing": 0.0,
"baffleSpacingOut": 0.0,
"baffleThickness": 0.0,
"BaffleOrientation": 0,
"baffleCut": 0.0,
"baffleCutBase": 0,
"nozzleInTubesideDiameter": 0.0,
"nozzleOutTubesideDiameter": 0.0,
"nozzleInShellsideDiameter": 0.0,
"nozzleOutShellsideDiameter": 0.0,
"clearanceTubeBaffle": 0.0,
"clearanceShellBaffle": 0.0,
"clearanceShellBundle": 0.0,
"sealingStrips": 0.0,
"modo": 0,
"f_install": 3.,
"Base_index": 0.0,
"Current_index": 0.0,
"tipoCoste": 0,
"materialCoste": 0,
"P_dis": 0.0}
indiceCostos = 2
TEXT_METHOD_TUBE_LAMINAR = ["Eubank-Proctor", "VDI mean Nusselt",
"Hausen", "Sieder-Tate"]
TEXT_METHOD_TUBE_TURBULENT = ["Sieder-Tate", "Colburn", "Dittus-Boelter",
"ESDU", "Gnielinski", "VDI mean Nusselt"]
TEXT_METHOD_SHELL = ["Stream analysis", "Bell-Delaware", "Kern"]
TEXT_CLASS = ["TEMA R", "TEMA B", "TEMA C"]
TEXT_FRONTHEAD = [
"A - " + translate("equipment", "Channel & Removable Cover"),
"B - " + translate("equipment", "Bonnet"),
"C - " + translate("equipment", "Removable Bundle"),
"D - " + translate("equipment", "Special High Pressure Closure"),
"N - " + translate("equipment", "Channel with Tubesheet & Removable Cover")]
TEXT_SHELL = [
"E - " + translate("equipment", "One Pass"),
"F - " + translate("equipment", "Two Pass"),
"G - " + translate("equipment", "Split Flow"),
"H - " + translate("equipment", "Double Split Flow"),
"J - " + translate("equipment", "Divided Flow"),
"K - " + translate("equipment", "Kettle Reboiler"),
"X - " + translate("equipment", "Cross Flow")]
TEXT_REARHEAD = [
"L - " + translate("equipment", "Fixed Tubesheet (A head)"),
"M - " + translate("equipment", "Fixed Tubesheet (B head)"),
"N - " + translate("equipment", "Fixed Tubesheet (N head)"),
"P - " + translate("equipment", "Outside Packed Flt Head"),
"S - " + translate("equipment", "Flt Head with Backing Dev"),
"T - " + translate("equipment", "Pull Throught Flt Heat"),
"U - " + translate("equipment", "U-Tube Bundle"),
"W - " + translate("equipment", "Exit Sealed Flt Tubesheet")]
TEXT_ORIENTATION = [
translate("equipment", "Horizontal"),
translate("equipment", "Vertical")]
TEXT_DISTRIBUTION_TUBE = [
translate("equipment", "Triangular")+", 30º",
translate("equipment", "Diamond")+", 45º",
translate("equipment", "Rotated Triangular")+", 60º",
translate("equipment", "Square")+", 90º"]
TEXT_BAFFLE_TYPE = [
translate("equipment", "Single segmental"),
translate("equipment", "Double segmental"),
translate("equipment", "Triple segmental"),
translate("equipment", "No tubes in window"),
translate("equipment", "Disk & donut"),
translate("equipment", "Rod")]
TEXT_COST_TYPE = [
translate("equipment", "Fixed Head"),
translate("equipment", "Kettle Reboiler"),
translate("equipment", "U-Tube")]
TEXT_COST_MATERIAL = [
translate("equipment", "Carbon Steel"),
translate("equipment", "Stainless Steel 316"),
translate("equipment", "Stainless Steel 304"),
translate("equipment", "Stainless Steel 347"),
translate("equipment", "Nickel 200"),
translate("equipment", "Monel 400"),
translate("equipment", "Inconel 600"),
translate("equipment", "Incoloy 825"),
translate("equipment", "Titanium"),
translate("equipment", "Hastelloy")]
@property
def isCalculable(self):
if self.kwargs["f_install"] and self.kwargs["Base_index"] and \
self.kwargs["Current_index"]:
self.statusCoste = True
else:
self.statusCoste = False
if not self.kwargs["entradaTubo"]:
self.msg = translate("equipment", "undefined tubeside input")
self.status = 0
return
if not self.kwargs["entradaCarcasa"]:
self.msg = translate("equipment", "undefined shellside input")
self.status = 0
return
return True
[docs]
def calculo(self):
if self.kwargs["modo"]:
#Diseño
pass
else: # Evaluación
N = self.kwargs["NTube"]
De = unidades.Length(self.kwargs["DeTube"])
Di = unidades.Length(De-2*self.kwargs["wTube"])
L = unidades.Length(self.kwargs["LTube"])
#TubeSide
rho = self.kwargs["entradaTubo"].Liquido.rho
mu = self.kwargs["entradaTubo"].Liquido.mu
cp = self.kwargs["entradaTubo"].Liquido.cp
k = self.kwargs["entradaTubo"].Liquido.k
w = self.kwargs["entradaTubo"].Liquido.caudalmasico
beta = self.kwargs["entradaTubo"].Liquido.alfav
v = self.kwargs["entradaTubo"].Q/N*4/pi/Di
re = Re(D=Di, V=v, rho=rho, mu=mu)
pr = self.kwargs["entradaTubo"].Liquido.Pr
gz = Gz(w=w, cp=cp, k=k, L=L)
gr = Gr(beta=beta, T=self.kwargs["entradaTubo"].T, To=self.kwargs["entradaTubo"].T, L=L, mu=mu)
if re < 2300:
if self.kwargs["tubesideLaminar"] == 0:
Nu = h_tubeside_laminar_Eubank_Proctor(Pr=pr, Gz=gz, Gr=gr, D=Di, L=L)
elif self.kwargs["tubesideLaminar"] == 1:
Nu = h_tubeside_laminar_VDI(Re=re, Pr=pr, D=Di, L=L)
elif self.kwargs["tubesideLaminar"] == 2:
Nu = h_tubeside_laminar_Hausen(Gz=gz)
elif self.kwargs["tubesideLaminar"] == 3:
Nu = h_tubeside_laminar_Sieder_Tate(Gz=gz, Gr=gr)
else:
if self.kwargs["tubesideTurbulent"] == 0:
Nu = h_tubeside_turbulent_Sieder_Tate(Re=re, Pr=pr)
elif self.kwargs["tubesideTurbulent"] == 1:
Nu = h_tubeside_turbulent_Colburn(Re=re, Pr=pr)
elif self.kwargs["tubesideTurbulent"] == 2:
frio = self.kwargs["entradaCarcasa"] > self.kwargs["entradaTubo"]
Nu = h_tubeside_turbulent_Dittus_Boelter(Re=re, Pr=pr, calentamiento=frio)
elif self.kwargs["tubesideTurbulent"] == 3:
Nu = h_tubeside_turbulent_ESDU(Re=re, Pr=pr)
elif self.kwargs["tubesideTurbulent"] == 4:
Nu = h_tubeside_turbulent_Gnielinski(Re=re, Pr=pr, D=Di, L=L)
elif self.kwargs["tubesideTurbulent"] == 5:
line = self.kwargs["distribucionTube"] == 3
filas = self.kwargs["NTube"]**0.5
Nu = h_tubeside_turbulent_VDI(Re=re, Pr=pr, filas_tubos=filas, alineados=line)
hi = unidades.HeatTransfCoef(Nu*k/Di)
# ShellSide
if self.kwargs["shellsideSensible"] == 0:
h, DP = self.h_shellside_turbulent_Stream_Analysis()
elif self.kwargs["shellsideSensible"] == 1:
self.h_shellside_turbulent_Bell_Delaware()
else:
h = self.h_shelside_turbulent_Kern()
# Fouling
fi = self.kwargs["foulingShell"]
fo = self.kwargs["foulingTube"]
#F: Heat exchanger Design, Operation, Maintenance and Enhancement - Ali A. Rabah
# U=1/((1/ho+fo)/Ef+fw+fi(Ao/Ai)+Ao/Ai/hi)
# deltaT=(deltaT2-deltaT1)/log(deltaT2/deltaT1)
# U=1/(Do/hi/Di+Do*log(Do/Di)/2/k+1/ho)
# #TODO: añadir resistencias de depositos en la pared
# """Serth - Process heat transfer_ principles and applications pag 102"""
# q=U*Ao*deltaT
self.area = unidades.Area(25)
[docs]
def fw(self):
if self.kwargs["finned"]:
fw=self.kwargs["wTube"]/self.kwargs["kTube"]*((self.kwargs["DeTube"]+2*self.kwargs["Nfin"]*self.kwargs["heightFin"]*(self.kwargs["DeTube"]+self.kwargs["heightFin"]))/(self.kwargs["DeTube"]-self.kwargs["wTube"]))
else:
fw=self.kwargs["DeTube"]/2/self.kwargs["kTube"]*log(self.kwargs["DeTube"]/(self.kwargs["DeTube"]-2*self.kwargs["wTube"]))
return fw
[docs]
@staticmethod
def h_shellside_turbulent_Stream_Analysis():
"""Coeficiente de transferencia de calor por calor sensible en el parte de la carcasa en regimen turbulento
Serth - Process Heat Transfer - Principles and applications Cap. 7
"""
[docs]
def h_shellside_turbulent_Bell_Delaware(self):
"""Coeficiente de transferencia de calor por calor sensible en el parte de la carcasa en regimen turbulento
Serth - Process Heat Transfer - Principles and applications Cap. 6
"""
fi = 1
P = self.kwargs["pitch"]/self.kwargs["DeTube"]
mo = self.kwargs["entradaCarcasa"].caudalmasico
if self.kwargs["distribucionTube"] == 2:
Ptef = self.kwargs["pitch"]/2**0.5
else:
Ptef = self.kwargs["pitch"]
if self.kwargs["distribucionTube"] < 3:
tita_tp = unidades.Angle([30, 45, 60][self.kwargs["distribucionTube"]], "deg")
Pt_ = self.kwargs["pitch"]*cos(tita_tp)
else:
Pt_ = self.kwargs["pitch"]
Nc = self.kwargs["Ds"]*(1-2*self.kwargs["baffleCut"])/Pt_
Ncw = 0.8*self.kwargs["baffleCut"]*self.kwargs["Ds"]/Pt_
Dotl = self.kwargs["Ds"]-2*self.kwargs["clearanceShellBundle"]
Sm = self.kwargs["baffleSpacing"]*(self.kwargs["Ds"]-Dotl+(Dotl-self.kwargs["DeTube"])/Ptef*(self.kwargs["pitch"]-self.kwargs["DeTube"]))
G = mo/Sm
Re = self.kwargs["DeTube"]*G/self.kwargs["entradaCarcasa"].Liquido.mu
Pr = self.kwargs["entradaCarcasa"].Liquido.Pr
rho = self.kwargs["entradaCarcasa"].Liquido.rho
cp = self.kwargs["entradaCarcasa"].Liquido.cp
Dctl = Dotl-self.kwargs["DeTube"]
tita_ctl = 2*arccos(self.kwargs["Ds"]*(1-2*self.kwargs["baffleCut"])/Dctl)
Fc = 1+1./pi*(sin(tita_ctl)-tita_ctl)
Fw = 1./2/pi*(tita_ctl-sin(tita_ctl))
Stb = pi/8*((self.kwargs["DeTube"]+2*self.kwargs["clearanceTubeBaffle"])**2-self.kwargs["DeTube"]**2)*self.kwargs["NTube"]*(1+Fc)
tita_ds = 2*arccos(1-2*self.kwargs["baffleCut"])
Ssb = self.kwargs["Ds"]*self.kwargs["clearanceShellBaffle"]*(pi-0.5*tita_ds)
Sb = self.kwargs["baffleSpacing"]*(self.kwargs["Ds"]-Dotl)
Sw = 1./8*self.kwargs["Ds"]**2*(tita_ds-sin(tita_ds))-1./4*self.kwargs["NTube"]*Fw*pi*self.kwargs["DeTube"]**2
Dw = 4*Sw/(pi*self.kwargs["DeTube"]*self.kwargs["NTube"]*0.5*(1-Fc)+self.kwargs["Ds"]*tita_ds)
Jc = 0.55+0.72*Fc
rs = Ssb/(Ssb+Stb)
rl = (Ssb+Stb)/Sm
Jl = 0.44*(1-rs)+(1-0.44*(1-rs))*exp(-2.2*rl)
Rl = exp(-1.33*(1+rs)*rl**(0.8-0.15*(1+rs)))
rss = self.kwargs["sealingStrips"]/Nc
if rss < 0.5:
if Re < 100:
Cj = 1.35
Cr = 4.5
else:
Cj = 1.25
Cr = 3.7
Jb = exp(-Cj*Sb/Sm*(1-(2*rss)**(1./3)))
Rb = exp(-Cr*Sb/Sm*(1-(2*rss)**(1./3)))
else:
Jb = 1.
Rb = 1.
if Re < 100:
n1 = 1./3
n2 = 1.
else:
n1 = 0.6
n2 = 0.2
nb = self.kwargs["LTube"]/self.kwargs["baffleSpacing"]
if self.kwargs["baffleSpacingIn"] > self.kwargs["baffleSpacing"]:
nb += 1
if self.kwargs["baffleSpacingOut"] > self.kwargs["baffleSpacing"]:
nb += 1
Js = (nb-1+(self.kwargs["baffleSpacingIn"]/self.kwargs["baffleSpacing"])**(1-n1)+(self.kwargs["baffleSpacingOut"]/self.kwargs["baffleSpacing"])**(1-n1))/(nb-1+(self.kwargs["baffleSpacingIn"]/self.kwargs["baffleSpacing"])+self.kwargs["baffleSpacingOut"]/self.kwargs["baffleSpacing"])
Rs = 0.5*((self.kwargs["baffleSpacing"]/self.kwargs["baffleSpacingIn"])**(2-n2)+(self.kwargs["baffleSpacing"]/self.kwargs["baffleSpacingOut"])**(2-n2))
Nct = (nb+1)*(Nc+Ncw)
if Re <= 20:
Jr = (10/Nct)**0.18
elif Re >= 100:
Jr = 1.
else: # Interpolacion entre los valores de arriba
Jr = 0.853379+0.0014662*Re
# Table 6.1
if self.kwargs["distribucionTube"] == 1:
a3, a4 = 0, 0
if Re < 10:
a1 = 1.55
a2 = -0.667
elif Re < 100:
a1 = 0.498
a2 = -0.656
elif Re < 1000:
a1 = 0.73
a2 = -0.500
elif Re < 10000:
a1 = 0.37
a2 = -0.396
else:
a1 = 0.37
a2 = -0.396
a3 = 1.93
a4 = 0.5
elif self.kwargs["distribucionTube"] == 3:
a3, a4 = 0, 0
if Re < 10:
a1 = 0.97
a2 = -0.667
elif Re < 100:
a1 = 0.9
a2 = -0.631
elif Re < 1000:
a1 = 0.408
a2 = -0.46
elif Re < 10000:
a1 = 0.107
a2 = -0.266
else:
a1 = 0.37
a2 = -0.395
a3 = 1.187
a4 = 0.37
else:
a3, a4 = 0, 0
if Re < 10:
a1 = 1.4
a2 = -0.667
elif Re < 100:
a1 = 1.36
a2 = -0.657
elif Re < 1000:
a1 = 0.593
a2 = -0.477
elif Re < 10000:
a1 = 0.321
a2 = -0.388
else:
a1 = 0.321
a2 = -0.388
a3 = 1.45
a4 = 0.519
if self.kwargs["distribucionTube"] == 1:
b3, b4 = 0, 0
if Re < 10:
b1 = 32
b2 = -1.
elif Re < 100:
b1 = 26.2
b2 = -0.913
elif Re < 1000:
b1 = 3.5
b2 = -0.476
elif Re < 10000:
b1 = 0.333
b2 = -0.136
else:
b1 = 0.303
b2 = -0.126
b3 = 6.59
b4 = 0.52
elif self.kwargs["distribucionTube"] == 3:
b3, b4 = 0, 0
if Re < 10:
b1 = 35.0
b2 = -1.
elif Re < 100:
b1 = 32.1
b2 = -0.963
elif Re < 1000:
b1 = 6.09
b2 = -0.602
elif Re < 10000:
b1 = 0.0815
b2 = 0.022
else:
b1 = 0.391
b2 = -0.148
b3 = 6.3
b4 = 0.378
else:
b3, b4 = 0, 0
if Re < 10:
b1 = 48.0
b2 = -1.
elif Re < 100:
b1 = 45.1
b2 = -0.973
elif Re < 1000:
b1 = 4.570
b2 = -0.476
elif Re < 10000:
b1 = 0.486
b2 = -0.152
else:
b1 = 0.372
b2 = -0.12
b3 = 7.0
b4 = 0.5
a = a3/(1+0.14*Re**a4) # Eq 6.3
b = b3/(1+0.14*Re**b4) # Eq 6.4
j = a1*(1.33/P)**a*Re**a2 # Eq 6.1
f = b1*(1.33/P)**b*Re**b2 # Eq 6.2
hid = j*cp*G*fi/Pr**(2./3)
h = unidades.HeatTransfCoef(hid*Jc*Jl*Jb*Jr*Js)
DPideal = 2*f*Nc*G**2/g/rho/fi
DPc = (nb-1)*DPideal*Rl*Rb
if Re > 100:
DPwideal = (2+0.6*Ncw)*mo**2/2/g/rho/Sm/Sw
else:
DPwideal = 26*nu*mo/g/(Sm*Sw)**0.5*(Ncw/P+self.kwargs["baffleCut"]*self.kwargs["Ds"]/Dw**2)+mo**2/g/rho/Sm/Sw
DPw = nb*DPwideal*Rl
DPe = 2*DPideal*(1+Ncw/Nc)*Rb*Rs
mon = mo/self.kwargs["parallel"]
DPn = 0
for D in self.kwargs["nozzleInShellsideDiameter"], self.kwargs["nozzleOutShellsideDiameter"]:
Ren = D*mon/self.kwargs["entradaCarcasa"].Liquido.mu
Sn = pi/4*D**2
if Ren > 100:
DPn += 2e-13*self.kwargs["serie"]*mon**2/Sn
else:
DPn += 4e-13*self.kwargs["serie"]*mon**2/Sn
DP = unidades.DeltaP(DPc+DPw+DPe+DPn)
return h, DP
[docs]
@staticmethod
def h_shelside_turbulent_Kern(Re, Pr):
"""Coeficiente de transferencia de calor por calor sensible en el parte de la carcasa en regimen turbulento
10<Re<1e6
kern pag 137
"""
return 0.36*Re**0.55*Pr**(1./3)*(mu/muw)**0.14
[docs]
def h_tubeside_laminar_condensation_Kern(self):
return 0.815*(k**3*rho_l*(rho_l-rho_g)*g*l/(pi*mu_l*Do*(T-Tw)))**0.25
[docs]
def h_tubeside_laminar_condensation_Nusselt(self):
return 0.72*eg**0.75*(k**3*rho_l*(rho_l-rho_g)*g*hlg/(mu_l*Do*(T-Tw)))**0.25
[docs]
def h_tubeSide_fined_Young(self):
"""Briggs, Katz, and Young, Chem.Eng. Prog., 59(11), 49–59 (1963)"""
return 0.1378*Re**0.718*Pr**(1./3)*(finSpacing/finHeight)**0.296
[docs]
def coste(self):
if self.kwargs["P_dis"]:
Pd = unidades.Pressure(self.kwargs["P_dis"])
else:
Pd = unidades.Pressure(max(self.kwargs["entradaTubo"].P, self.kwargs["entradaCarcasa"].P))
if self.kwargs["tipoCoste"] == 0: # Fired head
Fd = exp(-1.1156+0.09060*log(self.area.ft2))
elif self.kwargs["tipoCoste"] == 1: # Kettle reboiler
Fd = 1.35
else: # U-tubes
Fd = exp(-0.9816+0.0803*log(self.area.ft2))
g1 = [0., 0.8603, 0.8193, 0.6116, 1.5092, 1.2989, 1.204, 1.1854, 1.5420, 0.1549][self.kwargs["materialCoste"]]
g2 = [1., 0.23296, 0.15984, 0.22186, 0.60859, 0.43377, 0.50764, 0.49706, 0.42913, 0.51774][self.kwargs["materialCoste"]]
Fm = g1+g2*log(self.area.ft2)
if Pd.psi <= 300:
Fp = 0.771+0.04981*log(self.area.ft2)
elif Pd.psi <= 600:
Fp = 1.0305+0.0714*log(self.area.ft2)
else:
Fp = 1.14+0.12088*log(self.area.ft2)
C_base = exp(8.821-0.30863*log(self.area.ft2)+0.0681*log(self.area.ft2)**2)
C = Fd*Fm*Fp*C_base
self.C_adq = unidades.Currency(C * self.kwargs["Current_index"] / self.kwargs["Base_index"])
self.C_inst = unidades.Currency(self.C_adq*self.kwargs["f_install"])
if __name__ == "__main__":
from matplotlib import pyplot
Re = logspace(0, 5, 10000)
print(Re)
PtD = (1.25, 1.33, 1.5, 1.75)
for p in PtD:
ji = [jFactor(Rei, p, "") for Rei in Re]
pyplot.plot(Re, ji)
fi = [fFactor(Rei, p, "") for Rei in Re]
pyplot.plot(Re, fi)
pyplot.xscale("log")
pyplot.yscale("log")
pyplot.ylim(1e-2, 10)
pyplot.show()