Source code for equipment.pipe

#!/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 pipe equipment definition
###############################################################################


import os

from scipy.constants import g, pi
from tools.qt import translate

from lib import unidades
from lib.adimensional import Re
from lib.friction import f_friccion
from equipment.heatExchanger import Heat_Exchanger
from equipment.parents import equipment


[docs] class Pipe(equipment): """Class to model a pipe segment Parameters: entrada: Corriente instance to define the input stream to equipment metodo: Calculate method 0 - Single phase flow 1 - Water flow (Hazen-Williams equation) 2 - Steam flow (Fritzsche equation) 3 - Isothermic gas flow 4 - Multiphase flow (Método Baker) 5 - Multiphase flow (Método de Beggs and Brill) thermal: Thermal mode: 0 - Adiabatic 1 - Fix heat flow 2 - Heat exchanger calculation Material: Array with material properties 0 - Name 1 - Class 2 - Roughness, mm 3 - Catalog 4 - Di, mm 5 - Width, mm 6 - De, mm 7 - Weight, kg/m 8 - Volume, m³/100m 9 - Surface, m²/100m 10 - Index of material in catalog 11 - Index of dimenion in catalog Accesorios: Array with each fitting in pipe: Index with fitting type Index diameter K Count Type Diameter in mm Nominal diameter, in inch Text l: Length of pipe h: Head increase between input and output pipe K: Fittings total coefficient C: Parameter for Hazen-Williams equation T_ext: External temperatura of pipe for heat exchanger calculation U: Global heat transfer coeficient for pipe wall Q: Heat transfered by pipe wall Coste: Only available for steal pipes, Ref Darby pag 217 >>> from lib.corriente import Corriente >>> agua=Corriente(T=300, P=101325, caudalMasico=1, fraccionMolar=[1.]) >>> material=["Cast Iron", "Class A", 0.12192, '6"', 152.4, 11.43, \ 175.26, 42.07, 1.824, 55.06] >>> pipe=Pipe(entrada=agua, metodo=0, l=5, material=material) >>> print("%0.4f %6g %6g %6g" % (pipe.Di, pipe.V, pipe.Re, pipe.DeltaP)) 0.1524 0.0626815 9427.99 1.83620 """ title = translate("equipment", "Pipe") help = "" kwargs = { "entrada": None, "metodo": 0, "thermal": 0, "material": [], "accesorios": [], "l": 0.0, "h": 0.0, "K": 0.0, "C": 100., "T_ext": 0.0, "U": 0.0, "Q": 0.0, "f_install": 2.8, "Base_index": 0.0, "Current_index": 0.0} kwargsInput = ("entrada", ) kwargsValue = ("l", "h", "C") kwargsList = ("metodo", "thermal") calculateValue = ("DeltaP", "DeltaP_f", "DeltaP_ac", "DeltaP_h", "DeltaP_v", "DeltaP_100ft", "V", "f", "Re", "Tout") calculateCostos = ("C_adq", "C_inst") indiceCostos = 5 salida = [None] TEXT_METODO = ( translate("equipment", "Single Phase flow"), translate("equipment", "Water (Hazen-Williams)"), translate("equipment", "Steam (Fritzsche)"), translate("equipment", "Isotermic gas flow"), translate("equipment", "Two Phase flow (Baker method)"), translate("equipment", "Two Phase flow (Beggs and Brill method)")) TEXT_THERMAL = ( translate("equipment", "Adiabatic"), translate("equipment", "Heat flux"), translate("equipment", "Heat transfer")) @property def isCalculable(self): materialCoste = ['Stainless Steel (ANSI)', 'Steel Galvanised (ANSI)', 'Steel (ANSI)'] if self.kwargs["f_install"] and self.kwargs["Base_index"] and \ self.kwargs["Current_index"] and self.kwargs["material"] and \ self.kwargs["material"][0] in materialCoste: self.statusCoste = True else: self.statusCoste = False self.C_adq = unidades.Currency(None) self.C_inst = unidades.Currency(None) if not self.kwargs["entrada"]: self.msg = translate("equipment", "undefined input") self.status = 0 return if not self.kwargs["l"]: self.msg = translate("equipment", "undefined pipe length") self.status = 0 return if not self.kwargs["material"]: self.msg = translate("equipment", "undefined material") self.status = 0 return if self.kwargs["thermal"] == 1 and not self.kwargs["Q"]: self.msg = translate("equipment", "undefined heat flux") self.status = 0 return elif self.kwargs["thermal"] == 2 and \ (not self.kwargs["T_ext"] or not self.kwargs["U"]): self.msg = translate("equipment", "undefined heat transfer conditions") self.status = 0 return if self.kwargs["metodo"] == 1 and not self.kwargs["C"]: self.msg = translate("equipment", "undefined C William Factor") self.status = 0 return self.msg = "" self.status = 1 return True
[docs] def calculo(self): self.L = unidades.Length(self.kwargs["l"]) if self.kwargs["entrada"].x == 0: self.rho = self.kwargs["entrada"].Liquido.rho self.mu = self.kwargs["entrada"].Liquido.mu else: self.rho = self.kwargs["entrada"].Gas.rho self.mu = self.kwargs["entrada"].Gas.mu self.material = self.kwargs["material"][0] + " " + \ self.kwargs["material"][1] self.Dn = self.kwargs["material"][3] self.rugosidad = unidades.Length(self.kwargs["material"][2], "mm") self.De = unidades.Length(self.kwargs["material"][6], "mm") self.w = unidades.Length(self.kwargs["material"][5], "mm") self.Di = unidades.Length((self.De-2*self.w)) self.eD = unidades.Dimensionless(self.rugosidad/self.Di) self.seccion = unidades.Area(pi/4*self.Di**2) self.A = unidades.Area(pi*self.De*self.L) self.V = unidades.Speed(self.kwargs["entrada"].Q/self.seccion) self.Re = Re(self.Di, self.V, self.rho, self.mu) K = 0 for accesorio in self.kwargs["accesorios"]: K += accesorio[2]*accesorio[3] self.K = unidades.Dimensionless(K) self.DeltaP_h = unidades.Pressure(g*self.kwargs["h"]*self.rho) self.DeltaP_ac = unidades.Pressure(self.K*self.V**2/2*self.rho) self.f = f_friccion(self.Re, self.eD) self.DeltaP_f = self.__DeltaP_friccion() # TODO: self.DeltaP_v = unidades.Pressure(0) self.DeltaP = unidades.Pressure(self.DeltaP_h + self.DeltaP_ac + self.DeltaP_f + self.DeltaP_v) self.DeltaP_100ft = self.DeltaP*100/self.L.ft self.Pout = unidades.Pressure(self.kwargs["entrada"].P-self.DeltaP) if self.kwargs["thermal"] == 0: self.Tout = self.kwargs["entrada"].T self.Heat = unidades.Power(0) else: ch = Heat_Exchanger() ch(entrada=self.kwargs["entrada"], modo=self.kwargs["thermal"], Heat=self.kwargs["Q"], deltaP=self.DeltaP, A=self.A, U=self.kwargs["U"], Text=self.kwargs["Text"]) self.Tout = ch.salida[0].T self.Heat = ch.Heat self.salida = [self.kwargs["entrada"].clone(T=self.Tout, P=self.Pout)] self.Pin = self.kwargs["entrada"].P self.Pout = self.salida[0].P
def __DeltaP_friccion(self): """Método para el calculo de la perdida de presión""" if self.kwargs["metodo"] == 0: dp = unidades.DeltaP(self.L*self.V**2/self.Di*self.f*self.rho/2) elif self.kwargs["metodo"] == 1: p = (self.kwargs["entrada"].Q.galUSmin*self.L.ft**0.54/0.442 / self.Di.inch**2.63/self.kwargs["C"])**(1./0.54) dp = unidades.DeltaP(p, "psi") elif self.kwargs["metodo"] == 2: q = self.kwargs["entrada"].caudalmasico.lbh p = 2.1082*self.L.ft*q**1.85/self.rho.lbft3/1e7/self.Di.inch**4.97 dp = unidades.Pressure(p, "psi") elif self.kwargs["metodo"] == 3: pass elif self.kwargs["metodo"] == 4: pass elif self.kwargs["metodo"] == 5: pass return dp
[docs] def coste(self): """ Coste solo disponible para las tuberías de acero Ref Darby pag 217 kwargs: schedule: Clase de acero """ CI = self.kwargs["Current_index"] BI = self.kwargs["Base_index"] codigo = str(self.kwargs["material"][1]) if codigo in ('Sch. 40', 'Sch. 5S'): a = 30. p = 1.31 elif codigo in ('Sch. 80', 'Sch. 10S'): a = 38.1 p = 1.35 elif codigo in ('Sch. 160', 'Sch. 40S'): a = 55.3 p = 1.39 else: a = 0 p = 1 self.C_adq = unidades.Currency(a*self.Di.ft**p*self.L*CI/BI) self.C_inst = unidades.Currency(self.C_adq*self.kwargs["f_install"])
[docs] def writeListtoJSON(self, kwarg, key, value): """Personalizar en el caso de equipos con listas complejas""" kwarg_list = {} if key == "material": kwarg_list["material"] = value[0] kwarg_list["class"] = value[1] kwarg_list["rugosidad"] = value[2] kwarg_list["nominal"] = value[3] kwarg_list["Di"] = value[4] kwarg_list["w"] = value[5] kwarg_list["De"] = value[6] kwarg_list["weight"] = value[7] kwarg_list["volume"] = value[8] kwarg_list["area"] = value[9] kwarg_list["ind_material"] = value[10] kwarg_list["ind_size"] = value[11] elif key == "accesorios": for i, accesorio in enumerate(value): ac = {} ac["ind_equip"] = value[i][0] ac["ind_size"] = value[i][1] ac["K"] = value[i][2] ac["count"] = value[i][3] ac["type"] = value[i][4] ac["D_mm"] = value[i][5] ac["D_in"] = value[i][6] ac["description"] = value[i][7] kwarg_list[i] = ac kwarg[key] = kwarg_list
[docs] def readListFromJSON(self, data, key): """Read list from file, customize in entities with complex list""" kwarg = [] if key == "material": kwarg.append(data[key]["material"]) kwarg.append(data[key]["class"]) kwarg.append(data[key]["rugosidad"]) kwarg.append(data[key]["nominal"]) kwarg.append(data[key]["Di"]) kwarg.append(data[key]["w"]) kwarg.append(data[key]["De"]) kwarg.append(data[key]["weight"]) kwarg.append(data[key]["volume"]) kwarg.append(data[key]["area"]) kwarg.append(data[key]["ind_material"]) kwarg.append(data[key]["ind_size"]) elif key == "accesorios": for i, accesorio in data[key].items(): ac = [] ac.append(accesorio["ind_equip"]) ac.append(accesorio["ind_size"]) ac.append(accesorio["K"]) ac.append(accesorio["count"]) ac.append(accesorio["type"]) ac.append(accesorio["D_mm"]) ac.append(accesorio["D_in"]) ac.append(accesorio["description"]) kwarg.append(ac) return kwarg
[docs] def writeStatetoJSON(self, state): """Write instance parameter to file""" state["L"] = self.L state["rho"] = self.rho state["mu"] = self.mu state["material"] = self.material state["Dn"] = self.Dn state["rugosidad"] = self.rugosidad state["De"] = self.De state["w"] = self.w state["Di"] = self.Di state["eD"] = self.eD state["seccion"] = self.seccion state["A"] = self.A state["V"] = self.V state["Re"] = self.Re state["K"] = self.K state["DeltaP_h"] = self.DeltaP_h state["DeltaP_ac"] = self.DeltaP_ac state["f"] = self.f state["DeltaP_f"] = self.DeltaP_f state["DeltaP_v"] = self.DeltaP_v state["DeltaP"] = self.DeltaP state["DeltaP_100ft"] = self.DeltaP_100ft state["Pout"] = self.Pout state["Tout"] = self.Tout state["Heat"] = self.Heat state["Pin"] = self.Pin state["Pout"] = self.Pout state["statusCoste"] = self.statusCoste if self.statusCoste: 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.rho = unidades.Density(state["rho"]) self.mu = unidades.Viscosity(state["mu"]) self.material = state["material"] self.Dn = state["Dn"] self.rugosidad = unidades.Length(state["rugosidad"]) self.De = unidades.Length(state["De"]) self.w = unidades.Length(state["w"]) self.Di = unidades.Length(state["Di"]) self.eD = unidades.Dimensionless(state["eD"]) self.seccion = unidades.Area(state["seccion"]) self.A = unidades.Area(state["A"]) self.V = unidades.Speed(state["V"]) self.Re = unidades.Dimensionless(state["Re"]) self.K = unidades.Dimensionless(state["K"]) self.DeltaP_h = unidades.DeltaP(state["DeltaP_h"]) self.DeltaP_ac = unidades.DeltaP(state["DeltaP_ac"]) self.f = unidades.Dimensionless(state["f"]) self.DeltaP_f = unidades.DeltaP(state["DeltaP_f"]) self.DeltaP_v = unidades.DeltaP(state["DeltaP_v"]) self.DeltaP = unidades.DeltaP(state["DeltaP"]) self.DeltaP_100ft = unidades.Dimensionless(state["DeltaP_100ft"]) self.Tout = unidades.Temperature(state["Tout"]) self.Heat = unidades.Power(state["Heat"]) self.Pin = unidades.Pressure(state["Pin"]) self.Pout = unidades.Pressure(state["Pout"]) self.statusCoste = state["statusCoste"] if self.statusCoste: self.C_adq = unidades.Currency(state["C_adq"]) self.C_inst = unidades.Currency(state["C_inst"]) self.salida = [None]
[docs] def propTxt(self): txt = "#---------------" txt += translate("equipment", "Catalog") txt += "-----------------#" + os.linesep txt += self.propertiesToText(range(9)) if self.kwargs["accesorios"]: txt += os.linesep + "#---------------" txt += translate("equipment", "Fittings") txt += "-----------------#"+os.linesep txt += self.propertiesToText(9) for accesorio in self.kwargs["accesorios"]: txt += "%5i %-22s\t %s" % (accesorio[3], accesorio[7], accesorio[2]) + os.linesep txt += os.linesep + "#---------------" txt += translate("equipment", "Calculate properties") txt += "-----------------#" + os.linesep txt += self.propertiesToText(range(11, 24)) if self.kwargs["thermal"]: txt += self.propertiesToText(range(24, 26)) if self.statusCoste: txt += os.linesep+"#---------------" txt += translate("equipment", "Preliminary Cost Estimation") txt += "-----------------#" + os.linesep txt += self.propertiesToText(range(26, 31)) return txt
[docs] @classmethod def propertiesEquipment(cls): l = [(translate("equipment", "Material"), "material", str), (translate("equipment", "Nominal Diameter"), "Dn", str), (translate("equipment", "Length"), "L", unidades.Length), (translate("equipment", "Roughness"), "rugosidad", unidades.Length), (translate("equipment", "Internal Diamter"), "Di", unidades.Length), (translate("equipment", "External Diamter"), "De", unidades.Length), (translate("equipment", "Thickness"), "w", unidades.Length), (translate("equipment", "Transversal section"), "seccion", unidades.Area), (translate("equipment", "External Area"), "A", unidades.Area), (translate("equipment", "K total"), "K", unidades.Dimensionless), (translate("equipment", "Fittings"), "accesorios", None), (translate("equipment", "Method"), ("TEXT_METODO", "metodo"), str), (translate("equipment", "Input Pressure"), "Pin", unidades.Pressure), (translate("equipment", "Output Pressure"), "Pout", unidades.Pressure), (translate("equipment", "ΔP Total"), "DeltaP", unidades.DeltaP), (translate("equipment", "ΔP friction"), "DeltaP_f", unidades.DeltaP), (translate("equipment", "ΔP fittings"), "DeltaP_ac", unidades.DeltaP), (translate("equipment", "ΔP elevation"), "DeltaP_h", unidades.DeltaP), (translate("equipment", "ΔP acceleration"), "DeltaP_v", unidades.DeltaP), (translate("equipment", "Thermal Condition"), ("TEXT_THERMAL", "thermal"), str), (translate("equipment", "Fluid Speed"), "V", unidades.Speed), (translate("equipment", "Reynolds number"), "Re", unidades.Dimensionless), (translate("equipment", "Relative roughness"), "eD", unidades.Dimensionless), (translate("equipment", "Factor Friction"), "f", unidades.Dimensionless), (translate("equipment", "Output Temperature"), "Tout", unidades.Temperature), (translate("equipment", "Heat Transfer"), "Heat", unidades.Power), (translate("equipment", "Base index"), "Base_index", float), (translate("equipment", "Current index"), "Current_index", float), (translate("equipment", "Install factor"), "f_install", float), (translate("equipment", "Purchase Cost"), "C_adq", unidades.Currency), (translate("equipment", "Installed Cost"), "C_inst", unidades.Currency)] return l
[docs] def propertiesListTitle(self, index): lista = [] for accesorio in self.kwargs["accesorios"]: lista.append("%3i %s" % (accesorio[3], accesorio[7])) return lista
if __name__ == '__main__': import doctest doctest.testmod()