#!/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/>."""
###############################################################################
# library for heat exchanger equipment calculation
# - Heat_Exchanger
# - Fired_Heater
# - Shell_Tube
# - Hairpin
###############################################################################
from math import sqrt, exp, log
import os
from numpy import arccos, sin, cos, tanh
from scipy.constants import g, pi
from scipy.optimize import fsolve
from tools.qt import translate
from equipment.parents import equipment
from lib import unidades
from lib.adimensional import Re, Pr, Gr, Gz
from lib.friction import f_friccion
import lib.heatTransfer as ht
# from lib.heatTransfer import * # noqa
[docs]
class Heat_Exchanger(equipment):
"""Define a simple heat exchanger, only make energy balance
Parameters:
entrada: Corriente instance to define input stream
Heat: global heat value exchanged
Tout: Output temperature
DeltaT: Increase temperature in stream
A: area for heat exchange
U: Global coefficient of heat transmision
Text: Ambient external temperature
DeltaP: Opcional pressure losses of equipment
>>> from lib.corriente import Corriente
>>> agua = Corriente(T=300, P=101325., caudalMasico=1., fraccionMolar=[1.])
>>> Cambiador = Heat_Exchanger(entrada=agua, Tout=350)
>>> print("%6g" % Cambiador.HeatCalc.MJh)
753.063
"""
title = translate("equipment", "Heat Exchanger")
help = ""
kwargs = {
"entrada": None,
"Heat": 0.0,
"Tout": 0.0,
"DeltaT": 0.0,
"A": 0.0,
"U": 0.0,
"Text": 0.0,
"DeltaP": 0.0}
kwargsInput = ("entrada", )
kwargsValue = ("Heat", "Tout", "DeltaT", "A", "U", "Text", "DeltaP")
calculateValue = ("HeatCalc", "ToutCalc")
[docs]
def cleanOldValues(self, **kwargs):
"""Clean kwargs values for old heat exchanger definition"""
if kwargs.get("Tout", 0):
self.kwargs["DeltaT"] = 0
self.kwargs["Heat"] = 0
self.kwargs["A"] = 0
self.kwargs["U"] = 0
self.kwargs["Text"] = 0
elif kwargs.get("DeltaT", 0):
self.kwargs["Tout"] = 0
self.kwargs["Heat"] = 0
self.kwargs["A"] = 0
self.kwargs["U"] = 0
self.kwargs["Text"] = 0
elif kwargs.get("Heat", 0):
self.kwargs["Tout"] = 0
self.kwargs["DeltaT"] = 0
self.kwargs["A"] = 0
self.kwargs["U"] = 0
self.kwargs["Text"] = 0
self.kwargs.update(kwargs)
@property
def isCalculable(self):
"""
modo: unknown variable to calculate
1 - Known output temperature, calculate other variables
2 - known heat exchange
3 - known heat exchanger characteristic, calculate output stream
"""
if not self.kwargs["entrada"]:
self.msg = translate("equipment", "undefined input")
self.status = 0
self.modo = 0
return
if self.kwargs["A"] and self.kwargs["U"] and self.kwargs["Text"]:
self.modo = 3
elif self.kwargs["Heat"]:
self.modo = 2
elif self.kwargs["Tout"] or self.kwargs["DeltaT"]:
self.modo = 1
else:
self.msg = translate(
"equipment", "undefined output temperature specification")
self.status = 0
self.modo = 0
if self.modo:
self.msg = ""
self.status = 1
return True
[docs]
def calculo(self):
entrada = self.kwargs["entrada"]
self.deltaP = unidades.DeltaP(self.kwargs["DeltaP"])
self.HeatCalc = unidades.Power(self.kwargs["Heat"])
if self.kwargs["Tout"]:
Tout = unidades.Temperature(self.kwargs["Tout"])
elif self.kwargs["DeltaT"]:
Tout = unidades.Temperature(entrada.T+self.kwargs["DeltaT"])
A = unidades.Area(self.kwargs["A"])
U = unidades.HeatTransfCoef(self.kwargs["U"])
Text = unidades.Temperature(self.kwargs["Text"])
if self.modo == 1:
self.salida = [entrada.clone(T=Tout, P=entrada.P-self.deltaP)]
self.HeatCalc = unidades.Power(self.salida[0].h-entrada.h)
else:
if self.modo == 2:
self.HeatCalc = unidades.Power(0)
else:
self.HeatCalc = unidades.Power(A*U*(Text-entrada.T))
def f():
output = entrada.clone(T=T, P=entrada.P-self.deltaP)
return output.h-entrada.h-self.HeatCalc
T = fsolve(f, entrada.T)[0]
if T > max(Text, entrada.T) or T < min(Text, entrada.T):
T = self.Text
self.salida = [entrada.clone(T=T, P=entrada.P-self.deltaP)]
self.Tin = entrada.T
self.ToutCalc = self.salida[0].T
self.deltaT = unidades.DeltaT(self.ToutCalc-entrada.T)
[docs]
def propTxt(self):
txt = "#---------------"
txt += translate("equipment", "Calculate properties")
txt += "-----------------#"+os.linesep
txt += self.propertiesToText(range(5))
return txt
[docs]
@classmethod
def propertiesEquipment(cls):
l = [(translate("equipment", "Input Temperature"),
"Tin", unidades.Temperature),
(translate("equipment", "Output Temperature"),
"ToutCalc", unidades.Temperature),
(translate("equipment", "Temperature increase"),
"deltaT", unidades.DeltaT),
(translate("equipment", "Pressure increase"), "deltaP", unidades.DeltaP),
(translate("equipment", "Heat"), "HeatCalc", unidades.Power)]
return l
[docs]
def writeStatetoJSON(self, state):
"""Write instance parameter to file"""
state["Tin"] = self.Tin
state["ToutCalc"] = self.ToutCalc
state["deltaT"] = self.deltaT
state["deltaP"] = self.deltaP
state["HeatCalc"] = self.HeatCalc
[docs]
def readStatefromJSON(self, state):
"""Load instance parameter from saved file"""
self.Tin = unidades.Temperature(state["Tin"])
self.ToutCalc = unidades.Temperature(state["ToutCalc"])
self.deltaT = unidades.DeltaT(state["deltaT"])
self.deltaP = unidades.DeltaP(state["deltaP"])
self.HeatCalc = unidades.Power(state["HeatCalc"])
self.salida = [None]
[docs]
class Fired_Heater(equipment):
"""Class to model a fire heater
Parameters
----------
entrada : Corriente
Input stream to equipment
Tout : float
Desired output stream temperature, [K]
deltaP: float, optional
Pressure loss in equipment, [Pa]
Hmax: float, optional
Design heat transfer of equipment, maximum equipment capacity, [kJ/s]
eficiencia: float, optional, default 0.75
Thermic efficiency in combustion process, [-]
poderCalorifico: float, optional, default 900 Btu/stdft³
fuel heat power, [-]
Coste:
tipo:
0 - Box type
1 - Cylindrical type
subtipoBox:
0 - Process heater
1 - Pyrolysis
2 - Reformer without catalyst
subtipoCylindrical:
0 - Cylindrical
1 - Dowtherm
material:
0 - Carbon steel
1 - CrMo steel
2 - Stainless
P_dis: Design pressure of equipment, if no specified use the input
stream pressure
>>> from lib.corriente import Corriente
>>> agua = Corriente(T=400, P=101325., caudalMasico=1., fraccionMolar=[1.])
>>> cambiador = Fired_Heater(entrada=agua, Tout=450)
>>> print("%6g" % cambiador.Heat.MJh)
357.685
"""
title = translate("equipment", "Fired Heater")
help = os.environ["pychemqt"] + "doc/fireHeater.htm"
kwargs = {
"entrada": None,
"Tout": 0.0,
"deltaP": 0.0,
"Hmax": 0.0,
"eficiencia": 0.0,
"poderCalorifico": 0.0,
"f_install": 1.3,
"Base_index": 0.0,
"Current_index": 0.0,
"tipo": 0,
"subtipoBox": 0,
"subtipoCylindrical": 0,
"material": 0,
"P_dis": 0.0}
kwargsInput = ("entrada", )
kwargsValue = ("Tout", "deltaP", "Hmax", "eficiencia", "poderCalorifico",
"P_dis")
kwargsList = ("tipo", "subtipoBox", "subtipoCylindrical", "material")
calculateValue = ("CombustibleRequerido", "Heat")
calculateCostos = ("C_adq", "C_inst")
indiceCostos = 3
salida = [None]
TEXT_TIPO = [translate("equipment", "Box Type"),
translate("equipment", "Cylindrical type")]
TEXT_SUBTIPOBOX = [
translate("equipment", "Process heater"),
translate("equipment", "Pyrolysis"),
translate("equipment", "Reforme without catalysis")]
TEXT_SUBTIPOCYLINDRICAL = [
translate("equipment", "Cylindrical"),
translate("equipment", "Dowtherm")]
TEXT_MATERIAL = [translate("equipment", "Carbon steel"),
translate("equipment", "Cr-Mo steel"),
translate("equipment", "Stainless steel")]
@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["entrada"]:
self.msg = translate("equipment", "undefined input")
self.status = 0
return
if not self.kwargs["Tout"]:
self.msg = translate("equipment", "undefined output temperature condition")
self.status = 0
return
if self.kwargs["Tout"] <= self.kwargs["entrada"].T:
self.msg = translate("equipment", "bad output temperature condition")
self.status = 0
return
if not self.kwargs["eficiencia"]:
self.msg = translate("equipment", "using default efficiency")
self.status = 3
return True
if not self.kwargs["poderCalorifico"]:
self.msg = translate("equipment", "using default fuel calorific value")
self.status = 3
return True
self.msg = ""
self.status = 1
return True
[docs]
def calculo(self):
entrada = self.kwargs["entrada"]
self.Tout = unidades.Temperature(self.kwargs["Tout"])
self.deltaP = unidades.DeltaP(self.kwargs["deltaP"])
self.Hmax = unidades.Power(self.kwargs["Hmax"])
if self.kwargs["eficiencia"]:
eficiencia = self.kwargs["eficiencia"]
else:
eficiencia = 0.75
if self.kwargs["poderCalorifico"]:
poderCalorifico = self.kwargs["poderCalorifico"]
else:
poderCalorifico = 900
salida = entrada.clone(T=self.Tout, P=entrada.P-self.deltaP)
Ho = entrada.h
H1 = salida.h
Heat = unidades.Power(H1-Ho)
if self.Hmax and Heat > self.Hmax:
self.Heat = unidades.Power(self.Hmax)
To = (entrada.T+self.Tout)/2
T = fsolve(lambda T: entrada.clone(
T=T, P=entrada.P-self.deltaP).h-Ho-self.Hmax, To)[0]
self.salida = [entrada.clone(T=T, P=entrada.P-self.deltaP)]
else:
self.Heat = Heat
self.salida = [salida]
fuel = self.Heat.Btuh/poderCalorifico/eficiencia
self.CombustibleRequerido = unidades.VolFlow(fuel, "ft3h")
self.deltaT = unidades.DeltaT(self.salida[0].T-entrada.T)
self.eficiencia = unidades.Dimensionless(eficiencia)
self.poderCalorifico = unidades.Dimensionless(poderCalorifico)
self.Tin = entrada.T
self.Tout = self.salida[0].T
[docs]
def coste(self):
"""
tipo:
0 - Box type
1 - Cylindrical type
subtipoBox:
0 - Process heater
1 - Pyrolysis
2 - Reformer without catalyst
subtipoCylindrical:
0 - Cylindrical
1 - Dowtherm
material:
0 - Carbon steel
1 - CrMo steel
2 - Stainless
P_dis: Presión de diseño del equipo
"""
if self.kwargs["P_dis"]:
P_dis = unidades.Pressure(self.kwargs["P_dis"])
else:
P_dis = self.kwargs["entrada"].P
CI = self.kwargs["Current_index"]
BI = self.kwargs["Base_index"]
if self.kwargs["tipo"] == 0: # Boxtype
k = [25.5, 33.8, 45.][self.kwargs["material"]]
Fd = [0, 0.1, 0.35][self.kwargs["subtipoBox"]]
if P_dis.psi <= 500:
Fp = 0
elif P_dis.psi <= 1000:
Fp = 0.1
elif P_dis.psi <= 1500:
Fp = 0.15
elif P_dis.psi <= 2000:
Fp = 0.25
elif P_dis.psi <= 2500:
Fp = 0.4
else:
Fp = 0.6
C = k*(1+Fd+Fp)*self.Heat.MBtuh**0.86*1000
else: # Cylindrical
k = [27.3, 40.2, 42.][self.kwargs["material"]]
Fd = [0, 0.33][self.kwargs["subtipoCylindrical"]]
if P_dis.psi <= 500:
Fp = 0
elif P_dis.psi <= 1000:
Fp = 0.15
else:
Fp = 0.2
C = k*(1+Fd+Fp)*self.Heat.MBtuh**0.82*1000
self.P_dis = P_dis
self.C_adq = unidades.Currency(C * CI / BI)
self.C_inst = unidades.Currency(self.C_adq * self.kwargs["f_install"])
[docs]
def propTxt(self):
txt = "#---------------"
txt += translate("equipment", "Calculate properties")
txt += "-----------------#"+os.linesep
txt += self.propertiesToText(range(5))
stimated = " (%s)" % translate("equipment", "stimated")
txt += self.propertiesToText(5, kwCheck=True, kwSuffix=stimated,
kwKey="eficiencia", kwValue=0.0)
txt += self.propertiesToText(6, kwCheck=True, kwSuffix=stimated,
kwKey="poderCalorifico", kwValue=0.0)
txt += self.propertiesToText(7)
if self.statusCoste:
txt += os.linesep+"#---------------"
txt += translate("equipment", "Preliminary Cost Estimation")
txt += "-----------------#" + os.linesep
txt += self.propertiesToText(range(8, 18))
return txt
[docs]
@classmethod
def propertiesEquipment(cls):
l = [(translate("equipment", "Input Temperature"),
"Tin", unidades.Temperature),
(translate("equipment", "Output Temperature"),
"Tout", unidades.Temperature),
(translate("equipment", "Temperature increase"),
"deltaT", unidades.DeltaT),
(translate("equipment", "Pressure increase"), "deltaP", unidades.DeltaP),
(translate("equipment", "Maximum heat"), "Hmax", unidades.Power),
(translate("equipment", "Thermal Efficiency"),
"eficiencia", unidades.Dimensionless),
(translate("equipment", "Fuel Heating Value"),
"poderCalorifico", unidades.Dimensionless),
(translate("equipment", "Required Fuel"),
"CombustibleRequerido", unidades.VolFlow),
(translate("equipment", "Base index"), "Base_index", float),
(translate("equipment", "Current index"), "Current_index", float),
(translate("equipment", "Install factor"), "f_install", float),
(translate("equipment", "FireHeater type"), ("TEXT_TIPO", "tipo"), str),
(translate("equipment", "Cylindrical type"),
("TEXT_SUBTIPOCYLINDRICAL", "subtipoCylindrical"), str),
(translate("equipment", "Box type"),
("TEXT_SUBTIPOBOX", "subtipoBox"), str),
(translate("equipment", "Material"), ("TEXT_MATERIAL", "material"), str),
(translate("equipment", "Design Pressure"), "P_dis", unidades.Pressure),
(translate("equipment", "Purchase Cost"), "C_adq", unidades.Currency),
(translate("equipment", "Installed Cost"), "C_inst", unidades.Currency)]
return l
[docs]
def writeStatetoJSON(self, state):
"""Write instance parameter to file"""
state["Tout"] = self.Tout
state["deltaP"] = self.deltaP
state["Hmax"] = self.Hmax
state["Heat"] = self.Heat
state["CombustibleRequerido"] = self.CombustibleRequerido
state["deltaT"] = self.deltaT
state["eficiencia"] = self.eficiencia
state["poderCalorifico"] = self.poderCalorifico
state["Tin"] = self.Tin
state["statusCoste"] = self.statusCoste
if self.statusCoste:
state["P_dis"] = self.P_dis
state["C_adq"] = self.C_adq
state["C_inst"] = self.C_inst
[docs]
def readStatefromJSON(self, state):
"""Load instance parameter from saved file"""
self.Tout = unidades.Temperature(state["Tout"])
self.deltaP = unidades.DeltaP(state["deltaP"])
self.Hmax = unidades.Power(state["Hmax"])
self.Heat = unidades.Power(state["Heat"])
self.CombustibleRequerido = unidades.VolFlow(
state["CombustibleRequerido"])
self.deltaT = unidades.DeltaT(state["deltaT"])
self.eficiencia = unidades.Dimensionless(state["eficiencia"])
self.poderCalorifico = unidades.Dimensionless(state["poderCalorifico"])
self.Tin = unidades.Temperature(state["Tin"])
self.statusCoste = state["statusCoste"]
if self.statusCoste:
self.P_dis = unidades.Pressure(state["P_dis"])
self.C_adq = unidades.Currency(state["C_adq"])
self.C_inst = unidades.Currency(state["C_inst"])
self.salida = [None]
[docs]
class Hairpin(equipment):
"""Class to model double pipe section heat exchanger (hairpin)
Parameters:
entradaInterior: Corriente instance to define the fluid stream that
flow at internal section
entradaExterior: Corriente instance to define the fluid stream that
flow at external (anulli) section
modo: Calculate module
0 - Design
1 - Rating
flujo: Flow type
0 - Counterflow
1 - Parallelflow
orientacion: Pipe orientation
0 - Horizontal
1 - Vertical, internal down
2 - Vertical, internal up
metodo:
0 - Mean temperature
1 - Split the pipe in segments
tubesideLaminar: Method to calculate the global heat transfer
coefficient in laminar flow for tubeside
0 - Eubank-Proctor
1 - VDI mean Nusselt
2 - Hausen
3 - Sieder-Tate
tubesideTurbulent: Method to calculate the global heat transfer
coefficient in turbulent flow for tubeside
0 - Sieder-Tate
1 - Colburn
2 - Dittus-Boelter
3 - ESDU
4 - Gnielinski
5 - VDI mean Nusselt
LTube: Tube length
DeeTube: External diameter of annulli
DeTube: External diameter of internal pipe
DiTube: Internal diameter of internal pipe
wTube: Pipe width
rTube: Internal roughness of pipe
kTube: Thermal conductivity
tubeFouling: Fouling at tubeside
annulliFouling: Fouling at annulliside
hasTwistedTape: Boolean to use a twisted tape
twistedTape: Twisted tape insert instance
hasWireCoil: Boolean to use a wire coil insert
wireCoil: Wire-coil insert instance
hasRib: Boolean to use a tube with helical rib
rib: Helical rib instance
hasTwistedAnnuli: Boolean to use a twisted tape in annuli section
twistedAnnuli: Twisted tape in annulli section instance
finnedPipe: Boolean to use finned tube
hFin: Finned height
thicknessBaseFin: Thickness of the bottom of fin
thicknessTopFin: Thickness of the top of fin
rootDoFin: External diameter in the bottom of fin
kFin: Thermal conductiviti of material of fin
nFin: Fin count per meter of pipe
tubeTout: Output temperature of fluid in tubeside
annulliTout: Output temperature of fluid in annulliside
Cost:
material:
0 - Carbon steel/carbon steel
1 - Carbon steel/304 stainless
2 - Carbon steel/316 stainless
P_dis: Design pressure
>>> from lib.corriente import Corriente
>>> kw = {"ids": [62], "fraccionMolar": [1.]}
>>> caliente = Corriente(T=90+273.15, P=361540., caudalMasico=0.36, **kw)
>>> fria = Corriente(T=20+273.15, P=101325., caudalMasico=500/3600., **kw)
>>> Cambiador = Hairpin(entradaTubo=caliente, entradaExterior=fria, \
modo=1, DiTube=0.0525, DeTube=0.0603, LTube=2.5, \
DeeTube=0.0779, kTube=54, rTube=0.0459994e-3, \
annulliFouling=0.000352, tubeFouling=0.000176)
>>> print("%6g %6g" % (Cambiador.ReTube, Cambiador.ReAnnulli))
27783.3 1277.55
>>> print("%6g %6g" % (Cambiador.hTube.kWm2K, Cambiador.hAnnulli.kWm2K))
1555.53 52.8267
"""
title = translate("equipment", "Hairpin Heat Exchanger")
help = ""
kwargs = {
"entradaTubo": None,
"entradaExterior": None,
"modo": 0,
"flujo": 0,
"orientacion": 0,
"tubesideLaminar": 0,
"tubesideTurbulent": 0,
"annulliNuMethod": 0,
"metodo": 0,
"phase": 0,
"DeeTube": 0.0,
"DeTube": 0.0,
"DiTube": 0.0,
"wTube": 0.0,
"rTube": 0.0,
"kTube": 0.0,
"LTube": 0.0,
"nTube": 0.0,
"tubeFouling": 0.0,
"annulliFouling": 0.0,
"finnedPipe": 0,
"hFin": 0.0,
"thicknessBaseFin": 0.0,
"thicknessTopFin": 0.0,
"rootDoFin": 0.0,
"kFin": 0.0,
"nFin": 0,
"hasTwistedTape": False,
"twistedTape": None,
"hasWireCoil": False,
"wireCoil": None,
"hasRib": False,
"rib": None,
"hasTwistedAnnuli": False,
"twistedAnnuli": None,
"tubeTout": 0.0,
"tubeXout": -1.0,
"annulliTout": 0.0,
"annulliXout": -1.0,
"f_install": 3.,
"Base_index": 0.0,
"Current_index": 0.0,
"material": 0,
"P_dis": 0}
kwargsInput = ("entradaTubo", "entradaExterior")
kwargsValue = ("DeTube", "DiTube", "wTube", "rTube", "kTube", "LTube",
"nTube", "tubeFouling", "annulliFouling", "P_dis",
"tubeTout", "annulliTout")
kwargsList = ("modo", "flujo", "orientacion", "annulliNuMethod")
kwargsCheck = ("finnedPipe", )
kwargsMandatory = ("twistedTape", "twistedAnnuli", "wireCoil", "rib")
calculateValue = ("Q", "ToutAnnulli", "ToutTube", "U", "A", "L",
"deltaPTube", "deltaPAnnulli", "CF")
calculateCostos = ("C_adq", "C_inst")
indiceCostos = 2
TEXT_MODO = [
translate("equipment", "Design"),
translate("equipment", "Rating")]
TEXT_FLUJO = [
translate("equipment", "Counterflow"),
translate("equipment", "Parallelflow")]
TEXT_ORIENTACION = [
translate("equipment", "Horizontal"),
translate("equipment", "Vertical, (in down)"),
translate("equipment", "Vertical, (in up)")]
TEXT_MATERIAL = [
translate("equipment", "Carbon steel/carbon steel"),
translate("equipment", "Carbon steel/304 stainless"),
translate("equipment", "Carbon steel/316 stainless")]
TEXT_METHOD_ANNULI = [
"Gnielinski (2009)",
"Dirker-Meyer (2005)",
"Stein-Begell (1958)",
"Crookston-Rothfus-Kermode (1968)"]
CODE_FLUJO = ("CF", "PF")
@property
def isCalculable(self):
self.status = 1
self.msg = ""
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 internal stream input")
self.status = 0
return
if not self.kwargs["entradaExterior"]:
self.msg = translate("equipment", "undefined external stream input")
self.status = 0
return
if not self.kwargs["DeeTube"]:
self.msg = translate("equipment", "undefined pipe external diameter")
self.status = 0
return
self.statusPipe = 0
if self.kwargs["DeTube"] and self.kwargs["DiTube"]:
self.statusPipe = 1
elif self.kwargs["DeTube"] and self.kwargs["wTube"]:
self.statusPipe = 2
elif self.kwargs["DiTube"] and self.kwargs["wTube"]:
self.statusPipe = 3
else:
self.msg = translate("equipment", "undefined pipe diameters")
self.status = 0
return
if not self.kwargs["kTube"]:
self.msg = translate(
"equipment", "undefined pipe material thermal conductivity")
self.status = 0
return
self.statusFinned = 0
self.tubefinned = translate("equipment", "Bare Tube")
if self.kwargs["finnedPipe"]:
self.tubefinned = translate("equipment", "Finned Tube")
if self.kwargs["hFin"] and (self.kwargs["thicknessBaseFin"] or
self.kwargs["thicknessTopFin"]):
self.statusFinned = 1
self.msg = ""
else:
self.msg = translate("equipment", "fin not specified, using bare tube")
self.status = 3
if self.kwargs["modo"]:
if not self.kwargs["LTube"]:
self.msg = translate("equipment", "undefined pipe length")
self.status = 0
return
else:
self.statusOut = 0
o1 = self.kwargs["tubeTout"] or self.kwargs["tubeXout"] != -1
o2 = self.kwargs["annulliTout"] or self.kwargs["annulliXout"] != -1
if o1 and o2:
self.statusOut = 1
elif o1:
self.statusOut = 2
elif o2:
self.statusOut = 3
else:
self.msg = translate("equipment", "undefined output condition")
self.status = 0
return
return True
[docs]
def calculo(self):
# Define tipo de flujo
if self.kwargs["flujo"]:
self.flujo = "PF"
else:
self.flujo = "CF"
# Calculate pipe dimension
if self.statusPipe == 1:
self.De = unidades.Length(self.kwargs["DeTube"])
self.Di = unidades.Length(self.kwargs["DiTube"])
self.w = unidades.Length((self.De-self.Di)/2)
if self.kwargs["wTube"] and w != self.kwargs["wTube"]:
self.msg = translate("equipment", "Pipe thickness discard")
self.status = 3
elif self.statusPipe == 2:
self.De = unidades.Length(self.kwargs["DeTube"])
self.w = unidades.Length(self.kwargs["wTube"])
self.Di = unidades.Length(self.De-w*2)
else:
self.Di = unidades.Length(self.kwargs["DiTube"])
self.w = unidades.Length(self.kwargs["wTube"])
self.De = unidades.Length(self.Di+w*2)
self.Dee = unidades.Length(self.kwargs["DeeTube"])
self.rugosidad = unidades.Length(self.kwargs["rTube"])
self.k = unidades.ThermalConductivity(self.kwargs["kTube"])
self.fi = unidades.Fouling(self.kwargs["tubeFouling"])
self.fo = unidades.Fouling(self.kwargs["annulliFouling"])
if self.kwargs["modo"]:
self.rating()
else:
self.design()
eD = unidades.Dimensionless(self.kwargs["rTube"]/self.Di)
f = self._fTube(self.ReTube, eD)
dp_tube = self.L*self.VTube**2/self.Di*f*self.rhoTube/2
self.deltaPTube = unidades.DeltaP(dp_tube)
f_a = self._fAnnuli(self.ReAnnulli)
dp_annulli = self.L*self.VAnnulli**2/self.De*f_a*self.rhoAnnulli/2
self.deltaPAnnulli = unidades.DeltaP(dp_annulli)
self.salida = [
self.outTube.clone(P=self.outTube.P-self.deltaPTube),
self.outAnnulli.clone(P=self.outAnnulli.P-self.deltaPAnnulli)]
self.ToutTube = self.salida[0].T
self.ToutAnnulli = self.salida[1].T
self.XoutTube = self.salida[0].x
self.XoutAnnulli = self.salida[1].x
self.TinTube = self.kwargs["entradaTubo"].T
self.XinTube = self.kwargs["entradaTubo"].x
self.TinAnnulli = self.kwargs["entradaExterior"].T
self.XinAnnulli = self.kwargs["entradaExterior"].x
[docs]
def rating(self):
"""Rating of a specified pipe"""
# Input stream
inTube = self.kwargs["entradaTubo"]
inAnnulli = self.kwargs["entradaExterior"]
self.L = unidades.Length(self.kwargs["LTube"])
# Mean temperature method
if self.kwargs["metodo"] == 0:
self.phaseTube = self.ThermalPhase(inTube, inTube)
self.phaseAnnulli = self.ThermalPhase(inAnnulli, inAnnulli)
Ci = inTube.Liquido.cp*inTube.caudalmasico
Co = inAnnulli.Liquido.cp*inAnnulli.caudalmasico
Cmin = min(Ci, Co)
Cmax = max(Ci, Co)
C_ = Cmin/Cmax
self.A = unidades.Area(self.L*pi*self.De)
hi = self._hTube(inTube)
ho = self._hAnnulli(inAnnulli)
ni, no = self.rendimientoAletas(hi, ho)
self.Ug(hi, ni, ho, no)
NTU = self.A*self.U/Cmin
ep = ht.effectiveness(NTU, C_, self.CODE_FLUJO[self.kwargs["flujo"]])
self.Q = unidades.Power(ep*Cmin*abs(inTube.T-inAnnulli.T))
if inTube.T > inAnnulli.T:
QTube = self.Q
QAnnulli = -self.Q
else:
QTube = -self.Q
QAnnulli = self.Q
def f(T):
return inTube.clone(T=T).h-inTube.h+QTube
T = fsolve(f, inTube.T)[0]
self.outTube = inTube.clone(T=T)
def f(T):
return inAnnulli.clone(T=T).h-inAnnulli.h+QAnnulli
T = fsolve(f, inAnnulli.T)[0]
self.outAnnulli = inAnnulli.clone(T=T)
[docs]
def design(self):
"""Design a pipe to meet the specified heat transfer requeriments"""
# Input stream
inTube = self.kwargs["entradaTubo"]
inAnnulli = self.kwargs["entradaExterior"]
# Metodo temperaturas medias
if self.kwargs["metodo"] == 0:
# Calculate output condition and sensible/latent thermal situation,
# global thermal balance
if self.statusOut == 1:
if self.kwargs["tubeTout"]:
self.outTube = inTube.clone(T=self.kwargs["tubeTout"])
else:
self.outTube = inTube.clone(x=self.kwargs["tubeXout"])
if self.kwargs["annulliTout"]:
Tout = self.kwargs["annulliTout"]
self.outAnnulli = inAnnulli.clone(T=Tout)
else:
Xout = self.kwargs["annulliXout"]
self.outAnnulli = inAnnulli.clone(x=Xout)
Qo = abs(self.outAnnulli.h-inAnnulli.h)
Qi = abs(self.outTube.h-inTube.h)
self.Q = unidades.Power((Qo+Qi)/2.)
elif self.statusOut == 2:
if self.kwargs["tubeTout"]:
self.outTube = inTube.clone(T=self.kwargs["tubeTout"])
else:
self.outTube = inTube.clone(x=self.kwargs["tubeXout"])
Qi = abs(self.outTube.h-inTube.h)
self.Q = unidades.Power(Qi)
def f(T):
return inAnnulli.clone(T=T).h-inAnnulli.h-Qi
T = fsolve(f, inAnnulli.T)[0]
self.outAnnulli = inAnnulli.clone(T=T)
elif self.statusOut == 3:
if self.kwargs["annulliTout"]:
Tout = self.kwargs["annulliTout"]
self.outAnnulli = inAnnulli.clone(T=Tout)
else:
Xout = self.kwargs["annulliXout"]
self.outAnnulli = inAnnulli.clone(x=Xout)
Qo = abs(self.outAnnulli.h-inAnnulli.h)
self.Q = unidades.Power(Qo)
def f(T):
return inTube.clone(T=T).h-inTube.h-Qi
T = fsolve(f, inTube.T)[0]
self.outTube = inTube.clone(T=T)
self.phaseTube = self.ThermalPhase(inTube, self.outTube)
self.phaseAnnulli = self.ThermalPhase(inAnnulli, self.outAnnulli)
fluidTube = inTube.clone(T=(inTube.T+self.outTube.T)/2.)
T = (inAnnulli.T+self.outAnnulli.T)/2.
fluidAnnulli = inAnnulli.clone(T=T)
hi = self._hTube(fluidTube)
ho = self._hAnnulli(fluidAnnulli)
ni, no = self.rendimientoAletas(hi, ho)
self.Ug(hi, ni, ho, no)
if self.kwargs["flujo"]:
DTin = abs(inAnnulli.T-inTube.T)
DTout = abs(self.kwargs["tubeTout"]-self.kwargs["annulliTout"])
else:
DTin = abs(self.kwargs["tubeTout"]-inAnnulli.T)
DTout = abs(self.kwargs["annulliTout"]-inTube.T)
if DTin == DTout:
DTm = DTin
else:
DTm = (DTin-DTout)/log(DTin/DTout)
self.A = unidades.Area(self.Q/self.U/DTm)
self.L = unidades.Length(self.A/2/pi)
[docs]
def Ug(self, hi, ni, ho, no):
"""Calculate global heat transfer coefficient"""
Ui = self.De/self.Di/hi/ni
Ufi = self.De*self.fi/self.Di/ni
k = self.De*log(self.De/self.Di)/2/self.k
U = 1/(Ui+Ufi+k+self.fo/no+1/ho/no)
Uc = 1/(Ui+k+1/ho/no)
self.hTube = unidades.HeatTransfCoef(hi)
self.hAnnulli = unidades.HeatTransfCoef(ho)
self.U = unidades.HeatTransfCoef(U)
self.CF = unidades.Dimensionless(U/Uc)
self.OS = unidades.Dimensionless(Uc*(self.fi+self.fo))
[docs]
def ThermalPhase(self, input, output):
# Calculate thermal fundamentals
if input.x == output.x:
if input.x == 0:
phase = "Latent-Liquid"
else:
phase = "Latent-Vapor"
elif input.x < output.x:
phase = "Evaporator"
else:
phase = "Condenser"
return phase
[docs]
def rendimientoAletas(self, hi, ho):
"""Calculate thermal efficiency of fins"""
self.hFin = unidades.Length(self.kwargs["hFin"])
self.thicknessBaseFin = unidades.Length(self.kwargs["thicknessBaseFin"])
self.thicknessTopFin = unidades.Length(self.kwargs["thicknessTopFin"])
self.rootDoFin = unidades.Length(self.kwargs["rootDoFin"])
self.kFin = unidades.ThermalConductivity(self.kwargs["kFin"])
self.nFin = unidades.Dimensionless(self.kwargs["nFin"])
if self.kwargs["finnedPipe"]:
if self.statusFinned:
# For now only use circular fin
do = self.kwargs["rootDoFin"]
D = do + self.kwargs["hFin"] * 2
phi = (D/do-1)*(1+0.35*log(D/do))
w_b = self.kwargs["thicknessBaseFin"]
w_t = self.kwargs["thicknessTopFin"]
if w_b and w_t:
delta = (w_b + w_t) / 2
else:
delta = w_b + w_t
if self.kwargs["kFin"]:
kf = self.kwargs["kFin"]
else:
kf = self.kwargs["kTube"]
X = phi*do/2*sqrt(2*ho/kf/delta)
no = tanh(X)/X
else:
no = 1
# TODO: Define internal fins
ni = 1
else:
ni = 1
no = 1
return ni, no
[docs]
def _hTube(self, fluidTube):
"""Calculate convection heat trasnfer coefficient in tubeside"""
if fluidTube.x == 0:
fluido = fluidTube.Liquido
else:
fluido = fluidTube.Vapor
rho = fluido.rho
mu = fluido.mu
k = fluido.k
v = fluidTube.Q*4/pi/self.Di**2
re = Re(D=self.Di, V=v, rho=rho, mu=mu)
self.VTube = unidades.Speed(v)
self.rhoTube = rho
self.ReTube = unidades.Dimensionless(re)
pr = fluido.Prandt
beta = fluido.alfav
if self.kwargs["hasTwistedTape"] and self.kwargs["twistedTape"]:
Nu = self.kwargs["twistedTape"].Nu(re, pr, mu, mu, beta, 0, self.L)
elif self.kwargs["hasWireCoil"] and self.kwargs["wireCoil"]:
Nu = self.kwargs["wireCoil"].Nu(re, pr, self.Di, mu, mu)
elif self.kwargs["hasRib"] and self.kwargs["rib"]:
Nu = self.kwargs["rib"].Nu(re, pr, self.Di)
elif self.phaseTube[:6] == "Latent":
if re < 2300:
L = self.L
cp = fluido.cp
w = fluido.caudalmasico
gz = Gz(w=w, cp=cp, k=k, L=L)
gr = Gr(beta=beta, T=fluidTube.T, To=fluidTube.T, L=L, mu=mu)
if self.kwargs["tubesideLaminar"] == 0:
Nu = ht.h_tubeside_laminar_Eubank_Proctor(
Pr=pr, Gz=gz, Gr=gr, D=self.Di, L=L)
elif self.kwargs["tubesideLaminar"] == 1:
Nu = ht.h_tubeside_laminar_VDI(Re=re, Pr=pr, D=self.Di, L=L)
elif self.kwargs["tubesideLaminar"] == 2:
Nu = ht.h_tubeside_laminar_Hausen(Gz=gz)
elif self.kwargs["tubesideLaminar"] == 3:
Nu = ht.h_tubeside_laminar_Sieder_Tate(Gz=gz, Gr=gr)
else:
if self.kwargs["tubesideTurbulent"] == 0:
Nu = ht.h_tubeside_turbulent_Sieder_Tate(Re=re, Pr=pr)
elif self.kwargs["tubesideTurbulent"] == 1:
Nu = ht.h_tubeside_turbulent_Colburn(Re=re, Pr=pr)
elif self.kwargs["tubesideTurbulent"] == 2:
frio = self.kwargs["entradaCarcasa"].T > fluidTube.T
Nu = ht.h_tubeside_turbulent_Dittus_Boelter(
Re=re, Pr=pr, calentamiento=frio)
elif self.kwargs["tubesideTurbulent"] == 3:
Nu = ht.h_tubeside_turbulent_ESDU(Re=re, Pr=pr)
elif self.kwargs["tubesideTurbulent"] == 4:
Nu = ht.h_tubeside_turbulent_Gnielinski(
Re=re, Pr=pr, D=self.Di, L=L)
elif self.kwargs["tubesideTurbulent"] == 5:
line = self.kwargs["distribucionTube"] == 3
filas = self.kwargs["NTube"]**0.5
Nu = ht.h_tubeside_turbulent_VDI(
Re=re, Pr=pr, filas_tubos=filas, alineados=line)
if self.phaseTube == "Condenser":
if self.kwargs["orientation"] == 0:
# Condensation in horizontal tubes
if 0 < fluidTube.x < 1:
X_lockhart = ((1-fluidTube.x)/fluidTube.x)**0.9 * \
(fluidTube.Vapor.rho/fluidTube.Liquido.rho)**0.5 * \
(fluidTube.Liquido.mu/fluidTube.Vapor.mu)**0.1
G = fluidTube.caudalmasico*4/pi/self.Di**2
j = fluidTube.x*G/(
g*self.Di*fluidTube.Vapor.rho *
(fluidTube.Liquido.rho-fluidTube.Vapor.rho))**0.5
print((j, X_lockhart))
else:
# Condensation in vertical tubes
pass
print("Nu: ", Nu)
return unidades.HeatTransfCoef(Nu*k/self.Di)
[docs]
def _hAnnulli(self, fluidAnnulli):
"""Calculate convective heat transfer coefficient in annulli side"""
a = self.Dee/self.De
dh = self.Dee-self.De
rho = fluidAnnulli.Liquido.rho
mu = fluidAnnulli.Liquido.mu
k = fluidAnnulli.Liquido.k
v = fluidAnnulli.Q*4/pi/(self.Dee**2-self.De**2)
re = Re(D=dh, V=v, rho=rho, mu=mu)
self.VAnnulli = unidades.Speed(v)
self.rhoAnnulli = rho
self.ReAnnulli = unidades.Dimensionless(re)
pr = fluidAnnulli.Liquido.Prandt
if self.kwargs["hasTwistedAnnuli"] and self.kwargs["twistedAnnuli"]:
Nu = self.kwargs["twistedAnnuli"].Nu(re, pr, mu, mu)
else:
kw = {"method": self.kwargs["annulliNuMethod"], "L": self.L}
Nu = ht.Nu_anulli(re, pr, self.De, self.Dee, **kw)
return unidades.HeatTransfCoef(Nu*k/dh)
[docs]
def _fTube(self, Re, eD):
"""Calculate friction factor coefficient in tube side"""
if self.kwargs["hasTwistedTape"] and self.kwargs["twistedTape"]:
f = self.kwargs["twistedTape"].f(Re)
elif self.kwargs["hasWireCoil"] and self.kwargs["wireCoil"]:
f = self.kwargs["wireCoil"].f(Re, self.Di)
elif self.kwargs["hasRib"] and self.kwargs["rib"]:
f = self.kwargs["rib"].f(Re, self.Di)
else:
f = f_friccion(Re, eD)
print("f: ", f)
return f
[docs]
def _fAnnuli(self, Re):
"""Calculate friction factor coefficient in annulli side"""
if self.kwargs["hasTwistedAnnuli"] and self.kwargs["twistedAnnuli"]:
f = self.kwargs["twistedAnnuli"].f(Re)
else:
f = f_friccion(Re, geometry=6, Di=self.De, Do=self.Dee)
return f
[docs]
def coste(self):
self.material = self.kwargs["material"]
CI = self.kwargs["Current_index"]
BI = self.kwargs["Base_index"]
if self.kwargs["P_dis"]:
self.P_dis = unidades.Pressure(self.kwargs["P_dis"])
else:
self.P_dis = max(self.kwargs["entradaTubo"].P,
self.kwargs["entradaExterior"].P)
Pd = self.P_dis.psi
Fm = [1., 1.9, 2.2][self.kwargs["material"]]
if Pd < 4:
Fp = 1.
elif Pd < 6:
Fp = 1.1
else:
Fp = 1.25
C = Fm*Fp*900*self.A.ft2**0.18
self.C_adq = unidades.Currency(C * CI / BI)
self.C_inst = unidades.Currency(self.C_adq * self.kwargs["f_install"])
[docs]
def propTxt(self):
txt = "#---------------"
txt += translate("equipment", "Catalog")
txt += "-----------------#" + os.linesep
txt += self.propertiesToText(range(11))
# if self.kwargs["finnedPipe"]:
# txt += "\t" + self.propertiesToText(range(11, 17))
txt += os.linesep + "#---------------"
txt += translate("equipment", "Calculate properties")
txt += "-----------------#" + os.linesep
txt += self.propertiesToText(range(17, 20)) + os.linesep
txt += self.propertiesToText(range(20, 29)) + os.linesep # Tube
txt += self.propertiesToText(range(29, 38)) + os.linesep # Annulli
txt += self.propertiesToText(range(38, 42)) + os.linesep
if self.statusCoste:
txt += os.linesep+"#---------------"
txt += translate("equipment", "Preliminary Cost Estimation")
txt += "-----------------#" + os.linesep
txt += self.propertiesToText(range(42, 49))
return txt
[docs]
@classmethod
def propertiesEquipment(cls):
l = [(translate("equipment", "Length"), "L", unidades.Length),
(translate("equipment", "Pipe Internal Diameter"), "Di", unidades.Length),
(translate("equipment", "Pipe External Diameter"), "De", unidades.Length),
(translate("equipment", "Annulli External Diameter"),
"Dee", unidades.Length),
(translate("equipment", "Thickness"), "w", unidades.Length),
(translate("equipment", "Roughness"), "rugosidad", unidades.Length),
(translate("equipment", "External Area"), "A", unidades.Area),
(translate("equipment", "Thermal Conductivity"), "k",
unidades.ThermalConductivity),
(translate("equipment", "Internal Fouling"), "fi", unidades.Fouling),
(translate("equipment", "External Fouling"), "fo", unidades.Fouling),
(translate("equipment", "Finned Tube"), "tubefinned", str),
(translate("equipment", "Fin height"), "hFin", unidades.Length),
(translate("equipment", "Thickness at bottom of fin"),
"thicknessBaseFin", unidades.Length),
(translate("equipment", "Thickness at top of fin"),
"thicknessTopFin", unidades.Length),
(translate("equipment", "External diameter at bottom of fin"),
"rootDoFin", unidades.Length),
(translate("equipment", "Fin thermal conductivity"),
"kFin", unidades.ThermalConductivity),
(translate("equipment", "Fin count per meter"),
"nFin", unidades.Dimensionless),
(translate("equipment", "Mode"), ("TEXT_MODO", "modo"), str),
(translate("equipment", "Arrangement Flow"),
("TEXT_FLUJO", "flujo"), str),
(translate("equipment", "Layout"),
("TEXT_ORIENTACION", "orientacion"), str),
(translate("equipment", "Tube Mechanism"), "phaseTube", str),
(translate("equipment", "Tube Fluid Speed"), "VTube", unidades.Speed),
(translate("equipment", "Tube Reynolds"), "ReTube",
unidades.Dimensionless),
(translate("equipment", "Tube In Temperature"),
"TinTube", unidades.Temperature),
(translate("equipment", "Tube In Quality"),
"XinTube", unidades.Dimensionless),
(translate("equipment", "Tube Out Temperature"),
"ToutTube", unidades.Temperature),
(translate("equipment", "Tube Out Quality"),
"XoutTube", unidades.Dimensionless),
(translate("equipment", "ΔP Tube"), "deltaPTube", unidades.DeltaP),
(translate("equipment", "Tube heat transfer"),
"hTube", unidades.HeatTransfCoef),
(translate("equipment", "Annulli Mechanism"), "phaseAnnulli", str),
(translate("equipment", "Annulli Fluid Speed"),
"VAnnulli", unidades.Speed),
(translate("equipment", "Annulli Reynolds"),
"ReAnnulli", unidades.Dimensionless),
(translate("equipment", "Annulli In Temperature"),
"TinAnnulli", unidades.Temperature),
(translate("equipment", "Annulli In Quality"),
"XinAnnulli", unidades.Dimensionless),
(translate("equipment", "Annulli Out Temperature"),
"ToutAnnulli", unidades.Temperature),
(translate("equipment", "Annulli Out Quality"),
"XoutAnnulli", unidades.Dimensionless),
(translate("equipment", "ΔP Annulli", None),
"deltaPAnnulli", unidades.DeltaP),
(translate("equipment", "Annulli heat transfer"),
"hAnnulli", unidades.HeatTransfCoef),
(translate("equipment", "U"), "U", unidades.HeatTransfCoef),
(translate("equipment", "Q"), "Q", unidades.Power),
(translate("equipment", "Clean Factor"), "CF", unidades.Dimensionless),
(translate("equipment", "Over Surface"), "OS", unidades.Dimensionless),
(translate("equipment", "Base index"), "Base_index", float),
(translate("equipment", "Current index"), "Current_index", float),
(translate("equipment", "Install factor"), "f_install", float),
(translate("equipment", "Material"), ("TEXT_MATERIAL", "material"), str),
(translate("equipment", "Design Pressure"), "P_dis", unidades.Pressure),
(translate("equipment", "Purchase Cost"), "C_adq", unidades.Currency),
(translate("equipment", "Installed Cost"), "C_inst", unidades.Currency)]
return l
[docs]
def writeStatetoJSON(self, state):
"""Write instance parameter to file"""
state["L"] = self.L
state["Di"] = self.Di
state["De"] = self.De
state["Dee"] = self.Dee
state["w"] = self.w
state["rugosidad"] = self.rugosidad
state["A"] = self.A
state["k"] = self.k
state["fi"] = self.fi
state["fo"] = self.fo
state["tubefinned"] = self.tubefinned
state["hFin"] = self.hFin
state["thicknessBaseFin"] = self.thicknessBaseFin
state["thicknessTopFin"] = self.thicknessTopFin
state["rootDoFin"] = self.rootDoFin
state["kFin"] = self.kFin
state["nFin"] = self.nFin
state["phaseTube"] = self.phaseTube
state["VTube"] = self.VTube
state["ReTube"] = self.ReTube
state["TinTube"] = self.TinTube
state["XinTube"] = self.XinTube
state["ToutTube"] = self.ToutTube
state["XoutTube"] = self.XoutTube
state["deltaPTube"] = self.deltaPTube
state["hTube"] = self.hTube
state["phaseAnnulli"] = self.phaseAnnulli
state["VAnnulli"] = self.VAnnulli
state["ReAnnulli"] = self.ReAnnulli
state["TinAnnulli"] = self.TinAnnulli
state["XinAnnulli"] = self.XinAnnulli
state["ToutAnnulli"] = self.ToutAnnulli
state["XoutAnnulli"] = self.XoutAnnulli
state["deltaPAnnulli"] = self.deltaPAnnulli
state["hAnnulli"] = self.hAnnulli
state["U"] = self.U
state["Q"] = self.Q
state["CF"] = self.CF
state["OS"] = self.OS
state["statusCoste"] = self.statusCoste
if self.statusCoste:
state["P_dis"] = self.P_dis
state["C_adq"] = self.C_adq
state["C_inst"] = self.C_inst
[docs]
def readStatefromJSON(self, state):
"""Load instance parameter from saved file"""
self.L = unidades.Length(state["L"])
self.Di = unidades.Length(state["Di"])
self.De = unidades.Length(state["De"])
self.Dee = unidades.Length(state["Dee"])
self.w = unidades.Length(state["w"])
self.rugosidad = unidades.Length(state["rugosidad"])
self.A = unidades.Area(state["A"])
self.k = unidades.ThermalConductivity(state["k"])
self.fi = unidades.Fouling(state["fi"])
self.fo = unidades.Fouling(state["fo"])
self.tubefinned = state["tubefinned"]
self.hFin = unidades.Length(state["hFin"])
self.thicknessBaseFin = unidades.Length(state["thicknessBaseFin"])
self.thicknessTopFin = unidades.Length(state["thicknessTopFin"])
self.rootDoFin = unidades.Length(state["rootDoFin"])
self.kFin = unidades.ThermalConductivity(state["kFin"])
self.nFin = unidades.Dimensionless(state["nFin"])
self.phaseTube = state["phaseTube"]
self.VTube = unidades.Speed(state["VTube"])
self.ReTube = unidades.Dimensionless(state["ReTube"])
self.TinTube = unidades.Temperature(state["TinTube"])
self.XinTube = unidades.Dimensionless(state["XinTube"])
self.ToutTube = unidades.Temperature(state["ToutTube"])
self.XoutTube = unidades.Dimensionless(state["XoutTube"])
self.deltaPTube = unidades.DeltaP(state["deltaPTube"])
self.hTube = unidades.HeatTransfCoef(state["hTube"])
self.phaseAnnulli = state["phaseAnnulli"]
self.VAnnulli = unidades.Speed(state["VAnnulli"])
self.ReAnnulli = unidades.Dimensionless(state["ReAnnulli"])
self.TinAnnulli = unidades.Temperature(state["TinAnnulli"])
self.XinAnnulli = unidades.Dimensionless(state["XinAnnulli"])
self.ToutAnnulli = unidades.Temperature(state["ToutAnnulli"])
self.XoutAnnulli = unidades.Dimensionless(state["XoutAnnulli"])
self.deltaPAnnulli = unidades.DeltaP(state["deltaPAnnulli"])
self.hAnnulli = unidades.HeatTransfCoef(state["hAnnulli"])
self.U = unidades.HeatTransfCoef(state["U"])
self.Q = unidades.Power(state["Q"])
self.CF = unidades.Dimensionless(state["CF"])
self.OS = unidades.Dimensionless(state["OS"])
self.statusCoste = state["statusCoste"]
if self.statusCoste:
self.P_dis = unidades.Pressure(state["P_dis"])
self.C_adq = unidades.Currency(state["C_adq"])
self.C_inst = unidades.Currency(state["C_inst"])
self.salida = [None]
class Air_Cooler(equipment):
"""Clase que modela los enfriadores de aire"""
title = "Enfriador de aire"
help = ""
def coste(self, *args):
self._indicesCoste(*args)
C = 24.6*self.area.ft2**0.4*1000
self.C_adq = unidades.Currency(C*self.Current_index/self.Base_index)
self.C_inst = unidades.Currency(self.C_adq*self.f_install)
class Evaporator(equipment):
"""Clase que modela los evaporadores"""
title = "Evaporador"
help = ""
def coste(self, *args, **kwargs):
"""
tipo:
0 - Forced circulation
1 - Long tube
2 - Falling film
material:
forced circulation materials shell/tube
0 - Steel/copper
1 - Monel/cupronickel
2 - Nickel/nickel
Long tube evaporator materials shell/tube
0 - Steel/copper
1 - Steel/steel
2 - Steel/aluminum
3 - Nickel/nickel
"""
self._indicesCoste(*args)
self.tipo = kwargs.get("tipo", 0)
self.material = kwargs.get("material", 0)
A = self.area.ft2
if self.tipo == 0:
C_base = exp(5.9785-0.6056*log(A)+0.08514*log(A)**2)*1000
if self.material == 0:
Fm = 1.
elif self.material == 1:
Fm = 1.35
else:
Fm = 1.8
elif self.tipo == 1:
C_base = 0.36*A**0.85*1000
if self.material == 0:
Fm = 1.
elif self.material == 1:
Fm = 0.6
elif self.material == 2:
Fm = 0.7
else:
Fm = 3.3
else:
C_base = exp(3.2362-0.0126*log(A)+0.0244*log(A)**2)*1000
Fm = 1
C = Fm*C_base
self.C_adq = unidades.Currency(C*self.Current_index/self.Base_index)
self.C_inst = unidades.Currency(self.C_adq*self.f_install)
class Refrigeration(equipment):
"""Clase que modela las unidades de refrigeración"""
title = "Refrigerador"
help = ""
def Coste(self, *args, **kwargs):
self._indicesCoste(*args)
Tmax = self.Tmax.C
Q = self.calor.MBtuh
if Tmax >= 0:
F = 1.
elif Tmax >= -10:
F = 1.55
elif Tmax >= -20:
F = 2.1
elif Tmax >= -30:
F = 2.65
elif Tmax >= -3:
F = 3.2
else:
F = 4.
C = 146*F*Q**0.65*1000
C_adq = C*self.Current_index/self.Base_index
C_inst = C_adq*self.kwargs["f_install"]
self.C_adq = C_adq
self.C_inst = C_inst
def unsteady():
#========================================================================
#Input constants
#========================================================================
dtau = 0.001 # Set dimensionless time increments
dx = 0.05 # Set dimensionless length increments
Tmax = 0.95 # Set maximum dimensionless temperature
M = 21 # Counter for length discretization
#========================================================================
#Calculate parameters
#========================================================================
dx = 1.0/(M-1)
dx_x = 1.0/(M-1)
ratio = dtau/(dx**2)
const = 1.0 - 2.0*ratio
#========================================================================
#Set counters to zero
#========================================================================
i = 0
tau = 0.0
#========================================================================
# Set up arrays for solution and print
#========================================================================
Tnew = zeros(M, dtype = float)
T = zeros(M, dtype = float)
T[0] = 1.0
T[-1] = 1.0
print(("T initial = ", T))
#========================================================================
# I just pick 400 on trial and error for the total array
#========================================================================
T_sol = zeros((400,M), dtype = float)
T_sol[:,0] = 1.0
T_sol[:,-1] = 1.0
#========================================================================
# While loop to iterate until mid-point temperature reaches Tmax
#========================================================================
while T[10] < Tmax:
i = i + 1
tau = tau + dtau
#========================================================================
# Calculate new tempertures
#========================================================================
for j in range(1,M-1):
Tnew[j] = ratio*(T[j-1] + T[j+1]) + const*T[j]
#========================================================================
# Substitute new Temperatures in array for T
#========================================================================
for k in range(1,M-1):
T[k] = Tnew[k]
T_sol[i,k] = T[k]
print(("Tau and T_final =", tau, T_sol[i,:]))
#========================================================================
# Set up array for spatial values of x to plot
#========================================================================
x = [i*dx_x for i in range(M-1)]
x.append(1.0)
#========================================================================
# Plot the solutions
#=======================================================================
plot(x,T_sol[50,:])
plot(x,T_sol[100,:])
plot(x,T_sol[150,:])
plot(x,T_sol[250,:])
plot(x,T_sol[i,:])
#legend(['Tau = 0.5','Tau = 0.1','Tau = 0.15','Tau = 0.25',
#'Tau = final time'])
title('Normalized Slab Temperatures')
plt.show()
grid()
if __name__ == "__main__":
import doctest
doctest.testmod()
# from lib.corriente import Corriente
# aguaTubo=Corriente(T=283.15, P=101325., ids=[62], caudalMasico=10., fraccionMolar=[1.])
# aguaCarcasa=Corriente(T=370, P=101325., ids=[62], caudalMasico=1000., fraccionMolar=[1.])
# Ds=unidades.Length(19.25, "inch")
# Do=unidades.Length(1, "inch")
# L=unidades.Length(14, "ft")
# pt=unidades.Length(1.25, "inch")
# B=unidades.Length(3.85, "inch")
# dotl=unidades.Length(0.5*(19.25-17.91), "inch")
# cambiador = Shell_Tube(entradaTubo=aguaTubo, entradaCarcasa=aguaCarcasa, shellsideSensible=1, DShell=Ds, NTube=124, DeTube=Do, wTube=0.006, LTube=L, pitch=pt, distribucionTube=3, baffleSpacing=B, baffleSpacingIn=B, baffleSpacingOut=B, baffleCut=0.2, clearanceTubeBaffle=0.0004, clearanceShellBaffle=0.0025279, clearanceShellBundle=dotl, sealingStrips=0.1*9.24)
# from scipy import *
# from pylab import *
# import matplotlib.pyplot as plt
# unsteady()