class Pump(equipment): """Clase que modela un equipo de bombeo de líquidos Parámetros: entrada: instancia de la clase corriente que define la corriente de entrada en la bomba usarCurva: 0 - Funcionamiento fijo 1 - Funcionamiento siguiendo la curva característica incognita: Indica la variable a calcular en el caso de que se use la curva caracteristica 0 - Carga (incremento de presión) 1 - Caudal, en este caso sobreescribe el caudal de la corriente de entrada rendimiento: rendimiento de la bomba, no necesario si se ha definido la curva característica de la bomba deltaP: incremento de presión proporcionado por la bomba, no será necesario si se define la curva característica y es el caudal la variable a calcular, en atmosferas Pout: Presión a la salida de la bomba Carga: Cambio de presión basada en altura de columna de fluido curvaCaracteristica: array que define la curva característica, en la forma: [Dia, rpm, [Q1,..Qn], [h1,...,hn], [Pot1,...,Potn], [NPSH1,...NPSHn]]. diametro: diametro nominal bomba velocidad: velocidad de giro de la bomba Coste tipo_bomba 0 - Centrifugal pumps 1 - Reciprocating pumps 2 - Gear pumps 3 - Vertical mixed flow 4 - Vertical axial flow tipo_centrifuga 0 - One stage, 3550 rpm, VSC 1 - One stage, 1750 rpm, VSC 2 - One stage, 3550 rpm, HSC 3 - One stage, 1750 rpm, HSC 4 - Two stage, 3550 rpm, HSC 5 - Multistage, 3550 rpm, HSC Material 0 - Cast iron 1 - Case steel 2 - 304 or 316 fittings 3 - Stainless steel 304 or 316 4 - Case Gould's alloy no. 20 5 - Nickel 6 - Monel 7 - ISO B 8 - ISO B 9 - Titanium 10 - Hastelloy C 11 - Ductile iron 12 - Bronze motor: Tipo de motor 0 - Open drip-proof 1 - Totally enclosed, fan-cooled 2 - Explosion-proof rpm 0 - 3600 rpm 1 - 1800 rpm 2 - 1200 rpm >>> agua=Corriente(T=300, P=101325, caudalMasico=1, fraccionMolar=[1.]) >>> bomba=Pump(entrada=agua, rendimiento=0.75, deltaP=20*101325, tipo_bomba=1) >>> print bomba.power.hp 3.63596053358 >>> print bomba.C_inst 3493.24497823 """ title=QApplication.translate("pychemqt", "Pump") help="" kwargs={"entrada": None, "usarCurva": 0, "incognita": 0, "rendimiento": 0.0, "deltaP": 0.0, "Pout": 0.0, "Carga": 0.0, "curvaCaracteristica": [], "diametro": 0.0, "velocidad": 0.0, "f_install": 2.8, "Base_index": 0.0, "Current_index": 0.0, "tipo_bomba": 0, "tipo_centrifuga": 0, "material": 0, "motor": 0, "rpm": 0} kwargsInput=("entrada", ) kwargsCheck=("usarCurva", ) kwargsValue=("Pout", "deltaP", "rendimiento", "Carga", "diametro", "velocidad") kwargsList=("incognita", "tipo_bomba", "tipo_centrifuga", "material", "motor", "rpm") calculateValue=("PoutCalculada", "power", "headCalculada", "volflow", "rendimientoCalculado") calculateCostos=("C_bomba", "C_motor", "C_adq", "C_inst") indiceCostos=7 TEXT_BOMBA=[QApplication.translate("pychemqt", "Centrifugal"), QApplication.translate("pychemqt", "Reciprocating"), QApplication.translate("pychemqt", "Gear pump"), QApplication.translate("pychemqt", "Vertical mixed flow"), QApplication.translate("pychemqt", "Vertical axial flow")] TEXT_CENTRIFUGA=[QApplication.translate("pychemqt", "One stage, 3550 rpm, VSC"), QApplication.translate("pychemqt", "One stage, 1750 rpm, VSC"), QApplication.translate("pychemqt", "One stage, 3550 rpm, HSC"), QApplication.translate("pychemqt", "One stage, 1750 rpm, HSC"), QApplication.translate("pychemqt", "Two stage, 3550 rpm, HSC"), QApplication.translate("pychemqt", "Multistage, 3550 rpm, HSC")] TEXT_MATERIAL=[QApplication.translate("pychemqt", "Cast iron"), QApplication.translate("pychemqt", "Case steel"), QApplication.translate("pychemqt", "304 or 316 fittings"), QApplication.translate("pychemqt", "Stainless steel 304 or 316"), QApplication.translate("pychemqt", "Case Gould's alloy no. 20"), QApplication.translate("pychemqt", "Nickel"), QApplication.translate("pychemqt", "Monel (Ni-Cu)"), QApplication.translate("pychemqt", "ISO B"), QApplication.translate("pychemqt", "ISO C"), QApplication.translate("pychemqt", "Titanium"), QApplication.translate("pychemqt", "Hastelloy C (Ni-Fe-Mo)"), QApplication.translate("pychemqt", "Ductile iron"), QApplication.translate("pychemqt", "Bronze")] TEXT_MOTOR=[QApplication.translate("pychemqt", "Open drip-proof"), QApplication.translate("pychemqt", "Totally enclosed, fan-cooled"), QApplication.translate("pychemqt", "Explosion-proof")] TEXT_RPM=["3600 RPM", "1800 RPM", "1200 RPM"] @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=QApplication.translate("pychemqt", "undefined input") self.status=0 else: presion=self.kwargs["Pout"] or self.kwargs["deltaP"] or self.kwargs["Carga"] if self.kwargs["usarCurva"]: if self.kwargs["incognita"]: if presion and self.kwargs["curvaCaracteristica"]: self.msg="" self.status=1 return True elif presion: self.msg=QApplication.translate("pychemqt", "undefined pump curve") self.status=0 else: self.msg=QApplication.translate("pychemqt", "undefined out pressure condition") self.status=0 elif self.kwargs["curvaCaracteristica"]: self.msg="" self.status=1 return True else: self.msg=QApplication.translate("pychemqt", "undefined pump curve") self.status=0 else: if presion and self.kwargs["rendimiento"]: self.msg="" self.status=1 return True elif presion: self.msg=QApplication.translate("pychemqt", "undefined efficiency") self.status=0 else: self.msg=QApplication.translate("pychemqt", "undefined out pressure condition") self.status=0 def calculo(self): self.entrada=self.kwargs["entrada"] self.rendimientoCalculado=Dimensionless(self.kwargs["rendimiento"]) if self.kwargs["Pout"]: DeltaP=Pressure(self.kwargs["Pout"]-self.entrada.P) elif self.kwargs["deltaP"]: DeltaP=Pressure(self.kwargs["deltaP"]) elif self.kwargs["Carga"]: DeltaP=Pressure(self.kwargs["Carga"]*self.entrada.Liquido.rho*g) else: DeltaP=Pressure(0) if self.kwargs["usarCurva"]: if self.kwargs["diametro"]!=self.kwargs["curvaCaracteristica"][0] or self.kwargs["velocidad"]!=self.kwargs["curvaCaracteristica"][1]: self.curvaActual=self.calcularCurvaActual() else: self.curvaActual=self.kwargs["curvaCaracteristica"] self.Ajustar_Curvas_Caracteristicas() if not self.kwargs["usarCurva"]: head=Length(DeltaP/g/self.entrada.Liquido.rho) power=Power(head*g*self.entrada.Liquido.rho*self.entrada.Q/self.rendimientoCalculado) P_freno=Power(power*self.rendimientoCalculado) elif not self.kwargs["incognita"]: head=Length(polyval(self.CurvaHQ,self.entrada.Q)) self.DeltaP=Pressure(head*g*self.entrada.Liquido.rho) power=Power(self.entrada.Q*DeltaP) P_freno=Power(polyval(self.CurvaPotQ,self.entrada.Q)) self.rendimientoCalculado=Dimensionless(power/P_freno) else: head=Length(self.DeltaP/g/self.entrada.Liquido.rho) caudalvolumetrico=roots([self.CurvaHQ[0], self.CurvaHQ[1], self.CurvaHQ[2]-head])[0] power=Power(caudalvolumetrico*self.DeltaP) self.entrada=Corriente(self.entrada.T, self.entrada.P.atm, caudalvolumetrico*self.entrada.Liquido.rho*3600, self.entrada.mezcla, self.entrada.solido) P_freno=Power(polyval(self.CurvaPotQ,caudalvolumetrico)) self.rendimientoCalculado=Dimensionless(power/P_freno) self.headCalculada=head self.power=power self.P_freno=P_freno self.salida=[self.entrada.clone(P=self.entrada.P+DeltaP)] self.Pin=self.entrada.P self.PoutCalculada=self.salida[0].P self.Q=self.entrada.Q.galUSmin self.volflow=self.entrada.Q def Ajustar_Curvas_Caracteristicas(self): """Define la curva característica de la bomba a partir de los datos, todos ellos en forma de array de igual dimensión Q: caudal, m3/s h: carga, m mu: rendimiento NPSHr: carga neta de aspiración requerida por la bomba para no entrar en cavitación """ Q=r_[self.curvaActual[2]] h=r_[self.curvaActual[3]] Pot=r_[self.curvaActual[4]] NPSH=r_[self.curvaActual[5]] funcion_h = lambda p, x: p[0]*x**2+p[1]*x+p[2] # Función a ajustar residuo_h = lambda p, x, y: funcion_h(p, x) - y # Residuo inicio=r_[0, 0, 0] ajuste_h, exito_h=optimize.leastsq(residuo_h,inicio,args=(Q, h)) self.CurvaHQ=ajuste_h funcion_Pot = lambda p, x: p[0]*x**2+p[1]*x+p[2] # Función a ajustar residuo_Pot = lambda p, x, y: funcion_Pot(p, x) - y # Residuo inicio=r_[0, 0, 0] ajuste_Pot, exito_Pot=optimize.leastsq(residuo_Pot,inicio,args=(Q, Pot)) self.CurvaPotQ=ajuste_Pot funcion_NPSH = lambda p, x: p[0]+p[1]*exp(p[2]*x) # Función a ajustar residuo_NPSH = lambda p, x, y: funcion_NPSH(p, x) - y # Residuo inicio=r_[0, 0, 0] ajuste_NPSH, exito_NPSH=optimize.leastsq(residuo_NPSH,inicio,args=(Q, NPSH)) self.CurvaNPSHQ=ajuste_NPSH def calcularCurvaActual(self): """Método que define curvas caracteristica de la bomba a una velocidad de giro y diametro del propulsor diferente de la curva característica original haciendo uso de las leyes de afinidad, perry 10.25 Table 10.7""" D1=self.kwargs["curvaCaracteristica"][0] N1=self.kwargs["curvaCaracteristica"][1] D2=self.kwargs["diametro"] N2=self.kwargs["velocidad"] Q1=r_[self.kwargs["curvaCaracteristica"][2]] h1=r_[self.kwargs["curvaCaracteristica"][3]] Pot1=r_[self.kwargs["curvaCaracteristica"][4]] npsh1=r_[self.kwargs["curvaCaracteristica"][5]] Q2=Q1*D2/D1*N2/N1 h2=h1*N2**2/N1**2*D2**2/D1**2 Pot2=Pot1*N2**3/N1**3*D2**3/D1**3 npsh2=npsh1*N2**2/N1**2*D2**2/D1**2 #Esta relación no es tan fiable como las anteriores return [D2, N2, Q2, h2, Pot2, npsh2] def coste(self): HP=self.power.hp LnHP = log(self.power.hp) #Coste Bomba if self.kwargs["tipo_bomba"]==0: #Centrifugal pumps QH=log(self.Q*self.power.hp**0.5) Fm=[1., 1.35, 1.15, 2., 2., 3.5, 3.3, 4.95, 4.6, 9.7, 2.95, 1.15, 1.90] b1=[0., 5.1029, 0.0632, 2.0290, 13.7321, 9.8849][self.kwargs["tipo_centrifuga"]] b2=[0., -1.2217, 0.2744, -0.2371, -2.8304, -1.6164][self.kwargs["tipo_centrifuga"]] b3=[0., 0.0771, -0.0253, 0.0102, 0.1542, 0.0834][self.kwargs["tipo_centrifuga"]] Ft = exp(b1 + b2 * QH + b3 * QH**2) Cb=Fm[self.kwargs["material"]]*Ft*1.55*exp(8.833-0.6019*QH+0.0519*QH**2) elif self.kwargs["tipo_bomba"]==1: #Reciprocating pumps if self.kwargs["material"] == 0: #Case iron Cb=40.*self.Q**0.81 elif self.kwargs["material"] == 3: #316 Staineless steel Cb = 410.*self.Q**0.52 elif self.kwargs["material"] == 12: #Bronze Cb = 410.* 1.4 * self.Q**0.52 elif self.kwargs["material"] == 5: #Nickel Cb = 410. * 1.86 * self.Q**0.52 elif self.kwargs["material"] == 6: #Monel Cb = 410. * 2.20 * self.Q**0.52 else: #Material not available. Assume case iron Cb = 40. *self.Q**0.81 elif self.kwargs["tipo_bomba"]==2: #Gear pumps Cb=1000*exp(-0.0881+0.1986*log(self.Q)+0.0291*log(self.Q)**2) elif self.kwargs["tipo_bomba"]==3: #Vertical mixed flow Cb=0.036*self.Q**0.82*1000 elif self.kwargs["tipo_bomba"]==4: #Vertical axial flow Cb=0.02*self.Q**0.78*1000 C_bomba=Cb * self.kwargs["Current_index"] / self.kwargs["Base_index"] #Coste motor if self.kwargs["motor"] == 0: #Open, drip-proof if self.kwargs["rpm"] == 0 and HP <= 7.5: a1, a2, a3 = 4.8314, 0.0966, 0.10960 elif self.kwargs["rpm"] == 0 and 7.5< HP <= 250.: a1, a2, a3 = 4.1514, 0.5347, 0.05252 elif self.kwargs["rpm"] == 0 and HP > 250.: a1, a2, a3 = 4.2432, 1.03251, -0.03595 elif self.kwargs["rpm"] == 1 and HP <= 7.5: a1, a2, a3 = 4.7075, -0.01511, 0.22888 elif self.kwargs["rpm"] == 1 and 7.5< HP <= 250: a1, a2, a3 = 4.5212, 0.47242, 0.04820 elif self.kwargs["rpm"] == 1 and HP > 250.: a1, a2, a3 = 7.4044, -0.06464, 0.05448 elif self.kwargs["rpm"] == 2 and HP <= 7.5: a1, a2, a3 = 4.9298, 0.30118, 0.12630 elif self.kwargs["rpm"] == 2 and 7.5< HP <= 250: a1, a2, a3 = 5.0999, 0.35861, 0.06052 elif self.kwargs["rpm"] == 2 and HP > 250.: a1, a2, a3 = 4.6163, 0.88531, -0.02188 elif self.kwargs["motor"] == 1: #Totally enclosed, fan-cooled if self.kwargs["rpm"] == 0 and HP <= 7.5: a1, a2, a3 = 5.1058, 0.03316, 0.15374 elif self.kwargs["rpm"] == 0 and 7.5< HP <= 250.: a1, a2, a3 = 3.8544, 0.83311, 0.02399 elif self.kwargs["rpm"] == 0 and HP > 250.: a1, a2, a3 = 5.3182, 1.08470, -0.05695 elif self.kwargs["rpm"] == 1 and HP <= 7.5: a1, a2, a3 = 4.9687, -0.00930, 0.22616 elif self.kwargs["rpm"] == 1 and HP > 7.5: a1, a2, a3 = 4.5347, 0.57065, 0.04609 elif self.kwargs["rpm"] == 2 and HP <= 7.5: a1, a2, a3 = 5.1532, 0.28931, 0.14357 elif self.kwargs["rpm"] == 2 and HP > 7.5: a1, a2, a3 = 5.3858, 0.31004, 0.07406 elif self.kwargs["motor"] == 2: #Explosion-proof if self.kwargs["rpm"] == 0 and HP <= 7.5: a1, a2, a3 = 5.3934, -0.00333, 0.15475 elif self.kwargs["rpm"] == 0 and HP > 7.5: a1, a2, a3 = 4.4442, 0.60820, 0.05202 elif self.kwargs["rpm"] == 1 and HP <= 7.5: a1, a2, a3 = 5.2851, 0.00048, 0.19949 elif self.kwargs["rpm"] == 1 and HP > 7.5: a1, a2, a3 = 4.8178, 0.51086, 0.05293 elif self.kwargs["rpm"] == 2 and HP <= 7.5: a1, a2, a3 = 5.4166, 0.31216, 0.10573 elif self.kwargs["rpm"] == 2 and HP > 7.5: a1, a2, a3 = 5.5655, 0.31284, 0.07212 C_motor = 1.2 * exp(a1 + a2 * LnHP + a3 * LnHP**2) * self.kwargs["Current_index"] / self.kwargs["Base_index"] self.C_bomba=Currency(C_bomba) self.C_motor=Currency(C_motor) self.C_adq=Currency(C_bomba+C_motor) self.C_inst=Currency(self.C_adq*self.kwargs["f_install"]) def propTxt(self): txt="#---------------"+QApplication.translate("pychemqt", "Calculate properties")+"-----------------#"+os.linesep txt+="%-25s\t%s" %(QApplication.translate("pychemqt", "Input Pressure"), self.entrada.P.str)+os.linesep txt+="%-25s\t%s" %(QApplication.translate("pychemqt", "Output Pressure"), self.salida[0].P.str)+os.linesep txt+="%-25s\t%s" %(QApplication.translate("pychemqt", "Head"), self.headCalculada.str)+os.linesep txt+="%-25s\t%s" %(QApplication.translate("pychemqt", "Brake horsepower"), self.P_freno.str)+os.linesep txt+="%-25s\t%s" %(QApplication.translate("pychemqt", "Volumetric Flow"), self.volflow.str)+os.linesep txt+="%-25s\t%s" %(QApplication.translate("pychemqt", "Power"), self.power.str)+os.linesep txt+="%-25s\t %0.4f" %(QApplication.translate("pychemqt", "Efficiency"), self.rendimientoCalculado)+os.linesep txt+="%-25s\t %0.4f" %("Cp/Cv", self.entrada.Liquido.cp_cv)+os.linesep if self.statusCoste: txt+=os.linesep txt+="#---------------"+QApplication.translate("pychemqt", "Preliminary Cost Estimation")+"-----------------#"+os.linesep txt+="%-25s\t %0.2f" %(QApplication.translate("pychemqt", "Base index"), self.kwargs["Base_index"])+os.linesep txt+="%-25s\t %0.2f" %(QApplication.translate("pychemqt", "Current index"), self.kwargs["Current_index"])+os.linesep txt+="%-25s\t %0.2f" %(QApplication.translate("pychemqt", "Install factor"), self.kwargs["f_install"])+os.linesep txt+="%-25s\t %s" %(QApplication.translate("pychemqt", "Pump type"), self.TEXT_BOMBA[self.kwargs["tipo_bomba"]]) if self.kwargs["tipo_bomba"]==0: txt+=", "+self.TEXT_CENTRIFUGA[self.kwargs["tipo_centrifuga"]]+os.linesep else: txt+=os.linesep txt+="%-25s\t %s" %(QApplication.translate("pychemqt", "Material"), self.TEXT_MATERIAL[self.kwargs["material"]])+os.linesep txt+="%-25s\t%s" %(QApplication.translate("pychemqt", "Pump Cost"), self.C_bomba.str)+os.linesep txt+="%-25s\t %s, %s" %(QApplication.translate("pychemqt", "Motor type"), self.TEXT_MOTOR[self.kwargs["motor"]], self.TEXT_RPM[self.kwargs["rpm"]])+os.linesep txt+="%-25s\t%s" %(QApplication.translate("pychemqt", "Motor Cost"), self.C_motor.str)+os.linesep txt+="%-25s\t%s" %(QApplication.translate("pychemqt", "Purchase Cost"), self.C_adq.str)+os.linesep txt+="%-25s\t%s" %(QApplication.translate("pychemqt", "Installed Cost"), self.C_inst.str)+os.linesep return txt @classmethod def propertiesEquipment(cls): list=[(QApplication.translate("pychemqt", "Input Pressure"), "Pin", Pressure), (QApplication.translate("pychemqt", "Output Pressure"), "PoutCalculada", Pressure), (QApplication.translate("pychemqt", "Head"), "headCalculada", Length), (QApplication.translate("pychemqt", "Brake horsepower"), "P_freno", Power), (QApplication.translate("pychemqt", "Volumetric Flow"), "volflow", VolFlow), (QApplication.translate("pychemqt", "Power"), "power", Power), (QApplication.translate("pychemqt", "Efficiency"), "rendimientoCalculado", Dimensionless), (QApplication.translate("pychemqt", "Pump Type"), ("TEXT_BOMBA", "tipo_bomba"), str), (QApplication.translate("pychemqt", "Centrifuge Type"), ("TEXT_CENTRIFUGA", "tipo_centrifuga"), str), (QApplication.translate("pychemqt", "Material"), ("TEXT_MATERIAL", "material"), str), (QApplication.translate("pychemqt", "Motor Type"), ("TEXT_MOTOR", "motor"), str), (QApplication.translate("pychemqt", "Motor RPM"), ("TEXT_RPM", "rpm"), str), (QApplication.translate("pychemqt", "Pump Cost"), "C_bomba", Currency), (QApplication.translate("pychemqt", "Motor Cost"), "C_motor", Currency), (QApplication.translate("pychemqt", "Purchase Cost"), "C_adq", Currency), (QApplication.translate("pychemqt", "Installed Cost"), "C_inst", Currency)] return list def datamap2xls(self): datamap=(("PoutCalculada", "value", "H15"), ("PoutCalculada", "unit", "I15"), ("Pin", "value", "H16"), ("Pin", "unit", "I16"), ) return datamap def export2pdf(self): bomba=pdf("Bomba") bomba.bomba(self) bomba.dibujar() os.system("evince datasheet.pdf") def export2xls(self): font0 = xlwt.Font() font0.bold = True font0.height = 300 print font0.height style0 = xlwt.XFStyle() style0.font = font0 style1 = xlwt.XFStyle() style1.num_format_str = 'D-MMM-YY' wb = xlwt.Workbook() ws = wb.add_sheet('A Test Sheet') ws.write(0, 0, 'Test', style0) ws.write(2, 0, 1) ws.write(2, 1, 1) ws.write(2, 2, xlwt.Formula("A3+B3")) wb.save('datasheet.xls') os.system("gnumeric datasheet.xls")
class Pump(equipment): """Clase que modela un equipo de bombeo de líquidos Parámetros: entrada: instancia de la clase corriente que define la corriente de entrada en la bomba usarCurva: 0 - Funcionamiento fijo 1 - Funcionamiento siguiendo la curva característica incognita: Indica la variable a calcular en el caso de que se use la curva caracteristica 0 - Carga (incremento de presión) 1 - Caudal, en este caso sobreescribe el caudal de la corriente de entrada rendimiento: rendimiento de la bomba, no necesario si se ha definido la curva característica de la bomba deltaP: incremento de presión proporcionado por la bomba, no será necesario si se define la curva característica y es el caudal la variable a calcular, en atmosferas Pout: Presión a la salida de la bomba Carga: Cambio de presión basada en altura de columna de fluido curvaCaracteristica: array que define la curva característica, en la forma: [Dia, rpm, [Q1,..Qn], [h1,...,hn], [Pot1,...,Potn], [NPSH1,...NPSHn]]. diametro: diametro nominal bomba velocidad: velocidad de giro de la bomba Coste tipo_bomba 0 - Centrifugal pumps 1 - Reciprocating pumps 2 - Gear pumps 3 - Vertical mixed flow 4 - Vertical axial flow tipo_centrifuga 0 - One stage, 3550 rpm, VSC 1 - One stage, 1750 rpm, VSC 2 - One stage, 3550 rpm, HSC 3 - One stage, 1750 rpm, HSC 4 - Two stage, 3550 rpm, HSC 5 - Multistage, 3550 rpm, HSC Material 0 - Cast iron 1 - Case steel 2 - 304 or 316 fittings 3 - Stainless steel 304 or 316 4 - Case Gould's alloy no. 20 5 - Nickel 6 - Monel 7 - ISO B 8 - ISO B 9 - Titanium 10 - Hastelloy C 11 - Ductile iron 12 - Bronze motor: Tipo de motor 0 - Open drip-proof 1 - Totally enclosed, fan-cooled 2 - Explosion-proof rpm 0 - 3600 rpm 1 - 1800 rpm 2 - 1200 rpm >>> agua=Corriente(T=300, P=101325, caudalMasico=1, fraccionMolar=[1.]) >>> bomba=Pump(entrada=agua, rendimiento=0.75, deltaP=20*101325, tipo_bomba=1) >>> print bomba.power.hp 3.63596053358 >>> print bomba.C_inst 3493.24497823 """ title = QApplication.translate("pychemqt", "Pump") help = "" kwargs = { "entrada": None, "usarCurva": 0, "incognita": 0, "rendimiento": 0.0, "deltaP": 0.0, "Pout": 0.0, "Carga": 0.0, "curvaCaracteristica": [], "diametro": 0.0, "velocidad": 0.0, "f_install": 2.8, "Base_index": 0.0, "Current_index": 0.0, "tipo_bomba": 0, "tipo_centrifuga": 0, "material": 0, "motor": 0, "rpm": 0 } kwargsInput = ("entrada", ) kwargsCheck = ("usarCurva", ) kwargsValue = ("Pout", "deltaP", "rendimiento", "Carga", "diametro", "velocidad") kwargsList = ("incognita", "tipo_bomba", "tipo_centrifuga", "material", "motor", "rpm") calculateValue = ("PoutCalculada", "power", "headCalculada", "volflow", "rendimientoCalculado") calculateCostos = ("C_bomba", "C_motor", "C_adq", "C_inst") indiceCostos = 7 TEXT_BOMBA = [ QApplication.translate("pychemqt", "Centrifugal"), QApplication.translate("pychemqt", "Reciprocating"), QApplication.translate("pychemqt", "Gear pump"), QApplication.translate("pychemqt", "Vertical mixed flow"), QApplication.translate("pychemqt", "Vertical axial flow") ] TEXT_CENTRIFUGA = [ QApplication.translate("pychemqt", "One stage, 3550 rpm, VSC"), QApplication.translate("pychemqt", "One stage, 1750 rpm, VSC"), QApplication.translate("pychemqt", "One stage, 3550 rpm, HSC"), QApplication.translate("pychemqt", "One stage, 1750 rpm, HSC"), QApplication.translate("pychemqt", "Two stage, 3550 rpm, HSC"), QApplication.translate("pychemqt", "Multistage, 3550 rpm, HSC") ] TEXT_MATERIAL = [ QApplication.translate("pychemqt", "Cast iron"), QApplication.translate("pychemqt", "Case steel"), QApplication.translate("pychemqt", "304 or 316 fittings"), QApplication.translate("pychemqt", "Stainless steel 304 or 316"), QApplication.translate("pychemqt", "Case Gould's alloy no. 20"), QApplication.translate("pychemqt", "Nickel"), QApplication.translate("pychemqt", "Monel (Ni-Cu)"), QApplication.translate("pychemqt", "ISO B"), QApplication.translate("pychemqt", "ISO C"), QApplication.translate("pychemqt", "Titanium"), QApplication.translate("pychemqt", "Hastelloy C (Ni-Fe-Mo)"), QApplication.translate("pychemqt", "Ductile iron"), QApplication.translate("pychemqt", "Bronze") ] TEXT_MOTOR = [ QApplication.translate("pychemqt", "Open drip-proof"), QApplication.translate("pychemqt", "Totally enclosed, fan-cooled"), QApplication.translate("pychemqt", "Explosion-proof") ] TEXT_RPM = ["3600 RPM", "1800 RPM", "1200 RPM"] @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 = QApplication.translate("pychemqt", "undefined input") self.status = 0 else: presion = self.kwargs["Pout"] or self.kwargs[ "deltaP"] or self.kwargs["Carga"] if self.kwargs["usarCurva"]: if self.kwargs["incognita"]: if presion and self.kwargs["curvaCaracteristica"]: self.msg = "" self.status = 1 return True elif presion: self.msg = QApplication.translate( "pychemqt", "undefined pump curve") self.status = 0 else: self.msg = QApplication.translate( "pychemqt", "undefined out pressure condition") self.status = 0 elif self.kwargs["curvaCaracteristica"]: self.msg = "" self.status = 1 return True else: self.msg = QApplication.translate("pychemqt", "undefined pump curve") self.status = 0 else: if presion and self.kwargs["rendimiento"]: self.msg = "" self.status = 1 return True elif presion: self.msg = QApplication.translate("pychemqt", "undefined efficiency") self.status = 0 else: self.msg = QApplication.translate( "pychemqt", "undefined out pressure condition") self.status = 0 def calculo(self): self.entrada = self.kwargs["entrada"] self.rendimientoCalculado = Dimensionless(self.kwargs["rendimiento"]) if self.kwargs["Pout"]: DeltaP = Pressure(self.kwargs["Pout"] - self.entrada.P) elif self.kwargs["deltaP"]: DeltaP = Pressure(self.kwargs["deltaP"]) elif self.kwargs["Carga"]: DeltaP = Pressure(self.kwargs["Carga"] * self.entrada.Liquido.rho * g) else: DeltaP = Pressure(0) if self.kwargs["usarCurva"]: if self.kwargs["diametro"] != self.kwargs["curvaCaracteristica"][ 0] or self.kwargs["velocidad"] != self.kwargs[ "curvaCaracteristica"][1]: self.curvaActual = self.calcularCurvaActual() else: self.curvaActual = self.kwargs["curvaCaracteristica"] self.Ajustar_Curvas_Caracteristicas() if not self.kwargs["usarCurva"]: head = Length(DeltaP / g / self.entrada.Liquido.rho) power = Power(head * g * self.entrada.Liquido.rho * self.entrada.Q / self.rendimientoCalculado) P_freno = Power(power * self.rendimientoCalculado) elif not self.kwargs["incognita"]: head = Length(polyval(self.CurvaHQ, self.entrada.Q)) self.DeltaP = Pressure(head * g * self.entrada.Liquido.rho) power = Power(self.entrada.Q * DeltaP) P_freno = Power(polyval(self.CurvaPotQ, self.entrada.Q)) self.rendimientoCalculado = Dimensionless(power / P_freno) else: head = Length(self.DeltaP / g / self.entrada.Liquido.rho) caudalvolumetrico = roots( [self.CurvaHQ[0], self.CurvaHQ[1], self.CurvaHQ[2] - head])[0] power = Power(caudalvolumetrico * self.DeltaP) self.entrada = Corriente( self.entrada.T, self.entrada.P.atm, caudalvolumetrico * self.entrada.Liquido.rho * 3600, self.entrada.mezcla, self.entrada.solido) P_freno = Power(polyval(self.CurvaPotQ, caudalvolumetrico)) self.rendimientoCalculado = Dimensionless(power / P_freno) self.headCalculada = head self.power = power self.P_freno = P_freno self.salida = [self.entrada.clone(P=self.entrada.P + DeltaP)] self.Pin = self.entrada.P self.PoutCalculada = self.salida[0].P self.Q = self.entrada.Q.galUSmin self.volflow = self.entrada.Q def Ajustar_Curvas_Caracteristicas(self): """Define la curva característica de la bomba a partir de los datos, todos ellos en forma de array de igual dimensión Q: caudal, m3/s h: carga, m mu: rendimiento NPSHr: carga neta de aspiración requerida por la bomba para no entrar en cavitación """ Q = r_[self.curvaActual[2]] h = r_[self.curvaActual[3]] Pot = r_[self.curvaActual[4]] NPSH = r_[self.curvaActual[5]] funcion_h = lambda p, x: p[0] * x**2 + p[1] * x + p[ 2] # Función a ajustar residuo_h = lambda p, x, y: funcion_h(p, x) - y # Residuo inicio = r_[0, 0, 0] ajuste_h, exito_h = optimize.leastsq(residuo_h, inicio, args=(Q, h)) self.CurvaHQ = ajuste_h funcion_Pot = lambda p, x: p[0] * x**2 + p[1] * x + p[ 2] # Función a ajustar residuo_Pot = lambda p, x, y: funcion_Pot(p, x) - y # Residuo inicio = r_[0, 0, 0] ajuste_Pot, exito_Pot = optimize.leastsq(residuo_Pot, inicio, args=(Q, Pot)) self.CurvaPotQ = ajuste_Pot funcion_NPSH = lambda p, x: p[0] + p[1] * exp(p[2] * x ) # Función a ajustar residuo_NPSH = lambda p, x, y: funcion_NPSH(p, x) - y # Residuo inicio = r_[0, 0, 0] ajuste_NPSH, exito_NPSH = optimize.leastsq(residuo_NPSH, inicio, args=(Q, NPSH)) self.CurvaNPSHQ = ajuste_NPSH def calcularCurvaActual(self): """Método que define curvas caracteristica de la bomba a una velocidad de giro y diametro del propulsor diferente de la curva característica original haciendo uso de las leyes de afinidad, perry 10.25 Table 10.7""" D1 = self.kwargs["curvaCaracteristica"][0] N1 = self.kwargs["curvaCaracteristica"][1] D2 = self.kwargs["diametro"] N2 = self.kwargs["velocidad"] Q1 = r_[self.kwargs["curvaCaracteristica"][2]] h1 = r_[self.kwargs["curvaCaracteristica"][3]] Pot1 = r_[self.kwargs["curvaCaracteristica"][4]] npsh1 = r_[self.kwargs["curvaCaracteristica"][5]] Q2 = Q1 * D2 / D1 * N2 / N1 h2 = h1 * N2**2 / N1**2 * D2**2 / D1**2 Pot2 = Pot1 * N2**3 / N1**3 * D2**3 / D1**3 npsh2 = npsh1 * N2**2 / N1**2 * D2**2 / D1**2 #Esta relación no es tan fiable como las anteriores return [D2, N2, Q2, h2, Pot2, npsh2] def coste(self): HP = self.power.hp LnHP = log(self.power.hp) #Coste Bomba if self.kwargs["tipo_bomba"] == 0: #Centrifugal pumps QH = log(self.Q * self.power.hp**0.5) Fm = [ 1., 1.35, 1.15, 2., 2., 3.5, 3.3, 4.95, 4.6, 9.7, 2.95, 1.15, 1.90 ] b1 = [0., 5.1029, 0.0632, 2.0290, 13.7321, 9.8849][self.kwargs["tipo_centrifuga"]] b2 = [0., -1.2217, 0.2744, -0.2371, -2.8304, -1.6164][self.kwargs["tipo_centrifuga"]] b3 = [0., 0.0771, -0.0253, 0.0102, 0.1542, 0.0834][self.kwargs["tipo_centrifuga"]] Ft = exp(b1 + b2 * QH + b3 * QH**2) Cb = Fm[self.kwargs["material"]] * Ft * 1.55 * exp(8.833 - 0.6019 * QH + 0.0519 * QH**2) elif self.kwargs["tipo_bomba"] == 1: #Reciprocating pumps if self.kwargs["material"] == 0: #Case iron Cb = 40. * self.Q**0.81 elif self.kwargs["material"] == 3: #316 Staineless steel Cb = 410. * self.Q**0.52 elif self.kwargs["material"] == 12: #Bronze Cb = 410. * 1.4 * self.Q**0.52 elif self.kwargs["material"] == 5: #Nickel Cb = 410. * 1.86 * self.Q**0.52 elif self.kwargs["material"] == 6: #Monel Cb = 410. * 2.20 * self.Q**0.52 else: #Material not available. Assume case iron Cb = 40. * self.Q**0.81 elif self.kwargs["tipo_bomba"] == 2: #Gear pumps Cb = 1000 * exp(-0.0881 + 0.1986 * log(self.Q) + 0.0291 * log(self.Q)**2) elif self.kwargs["tipo_bomba"] == 3: #Vertical mixed flow Cb = 0.036 * self.Q**0.82 * 1000 elif self.kwargs["tipo_bomba"] == 4: #Vertical axial flow Cb = 0.02 * self.Q**0.78 * 1000 C_bomba = Cb * self.kwargs["Current_index"] / self.kwargs["Base_index"] #Coste motor if self.kwargs["motor"] == 0: #Open, drip-proof if self.kwargs["rpm"] == 0 and HP <= 7.5: a1, a2, a3 = 4.8314, 0.0966, 0.10960 elif self.kwargs["rpm"] == 0 and 7.5 < HP <= 250.: a1, a2, a3 = 4.1514, 0.5347, 0.05252 elif self.kwargs["rpm"] == 0 and HP > 250.: a1, a2, a3 = 4.2432, 1.03251, -0.03595 elif self.kwargs["rpm"] == 1 and HP <= 7.5: a1, a2, a3 = 4.7075, -0.01511, 0.22888 elif self.kwargs["rpm"] == 1 and 7.5 < HP <= 250: a1, a2, a3 = 4.5212, 0.47242, 0.04820 elif self.kwargs["rpm"] == 1 and HP > 250.: a1, a2, a3 = 7.4044, -0.06464, 0.05448 elif self.kwargs["rpm"] == 2 and HP <= 7.5: a1, a2, a3 = 4.9298, 0.30118, 0.12630 elif self.kwargs["rpm"] == 2 and 7.5 < HP <= 250: a1, a2, a3 = 5.0999, 0.35861, 0.06052 elif self.kwargs["rpm"] == 2 and HP > 250.: a1, a2, a3 = 4.6163, 0.88531, -0.02188 elif self.kwargs["motor"] == 1: #Totally enclosed, fan-cooled if self.kwargs["rpm"] == 0 and HP <= 7.5: a1, a2, a3 = 5.1058, 0.03316, 0.15374 elif self.kwargs["rpm"] == 0 and 7.5 < HP <= 250.: a1, a2, a3 = 3.8544, 0.83311, 0.02399 elif self.kwargs["rpm"] == 0 and HP > 250.: a1, a2, a3 = 5.3182, 1.08470, -0.05695 elif self.kwargs["rpm"] == 1 and HP <= 7.5: a1, a2, a3 = 4.9687, -0.00930, 0.22616 elif self.kwargs["rpm"] == 1 and HP > 7.5: a1, a2, a3 = 4.5347, 0.57065, 0.04609 elif self.kwargs["rpm"] == 2 and HP <= 7.5: a1, a2, a3 = 5.1532, 0.28931, 0.14357 elif self.kwargs["rpm"] == 2 and HP > 7.5: a1, a2, a3 = 5.3858, 0.31004, 0.07406 elif self.kwargs["motor"] == 2: #Explosion-proof if self.kwargs["rpm"] == 0 and HP <= 7.5: a1, a2, a3 = 5.3934, -0.00333, 0.15475 elif self.kwargs["rpm"] == 0 and HP > 7.5: a1, a2, a3 = 4.4442, 0.60820, 0.05202 elif self.kwargs["rpm"] == 1 and HP <= 7.5: a1, a2, a3 = 5.2851, 0.00048, 0.19949 elif self.kwargs["rpm"] == 1 and HP > 7.5: a1, a2, a3 = 4.8178, 0.51086, 0.05293 elif self.kwargs["rpm"] == 2 and HP <= 7.5: a1, a2, a3 = 5.4166, 0.31216, 0.10573 elif self.kwargs["rpm"] == 2 and HP > 7.5: a1, a2, a3 = 5.5655, 0.31284, 0.07212 C_motor = 1.2 * exp(a1 + a2 * LnHP + a3 * LnHP**2) * self.kwargs[ "Current_index"] / self.kwargs["Base_index"] self.C_bomba = Currency(C_bomba) self.C_motor = Currency(C_motor) self.C_adq = Currency(C_bomba + C_motor) self.C_inst = Currency(self.C_adq * self.kwargs["f_install"]) def propTxt(self): txt = "#---------------" + QApplication.translate( "pychemqt", "Calculate properties") + "-----------------#" + os.linesep txt += "%-25s\t%s" % (QApplication.translate( "pychemqt", "Input Pressure"), self.entrada.P.str) + os.linesep txt += "%-25s\t%s" % (QApplication.translate( "pychemqt", "Output Pressure"), self.salida[0].P.str) + os.linesep txt += "%-25s\t%s" % (QApplication.translate( "pychemqt", "Head"), self.headCalculada.str) + os.linesep txt += "%-25s\t%s" % (QApplication.translate( "pychemqt", "Brake horsepower"), self.P_freno.str) + os.linesep txt += "%-25s\t%s" % (QApplication.translate( "pychemqt", "Volumetric Flow"), self.volflow.str) + os.linesep txt += "%-25s\t%s" % (QApplication.translate( "pychemqt", "Power"), self.power.str) + os.linesep txt += "%-25s\t %0.4f" % (QApplication.translate( "pychemqt", "Efficiency"), self.rendimientoCalculado) + os.linesep txt += "%-25s\t %0.4f" % ("Cp/Cv", self.entrada.Liquido.cp_cv) + os.linesep if self.statusCoste: txt += os.linesep txt += "#---------------" + QApplication.translate( "pychemqt", "Preliminary Cost Estimation" ) + "-----------------#" + os.linesep txt += "%-25s\t %0.2f" % (QApplication.translate( "pychemqt", "Base index"), self.kwargs["Base_index"]) + os.linesep txt += "%-25s\t %0.2f" % (QApplication.translate( "pychemqt", "Current index"), self.kwargs["Current_index"]) + os.linesep txt += "%-25s\t %0.2f" % (QApplication.translate( "pychemqt", "Install factor"), self.kwargs["f_install"]) + os.linesep txt += "%-25s\t %s" % (QApplication.translate( "pychemqt", "Pump type"), self.TEXT_BOMBA[self.kwargs["tipo_bomba"]]) if self.kwargs["tipo_bomba"] == 0: txt += ", " + self.TEXT_CENTRIFUGA[ self.kwargs["tipo_centrifuga"]] + os.linesep else: txt += os.linesep txt += "%-25s\t %s" % ( QApplication.translate("pychemqt", "Material"), self.TEXT_MATERIAL[self.kwargs["material"]]) + os.linesep txt += "%-25s\t%s" % (QApplication.translate( "pychemqt", "Pump Cost"), self.C_bomba.str) + os.linesep txt += "%-25s\t %s, %s" % ( QApplication.translate("pychemqt", "Motor type"), self.TEXT_MOTOR[self.kwargs["motor"]], self.TEXT_RPM[self.kwargs["rpm"]]) + os.linesep txt += "%-25s\t%s" % (QApplication.translate( "pychemqt", "Motor Cost"), self.C_motor.str) + os.linesep txt += "%-25s\t%s" % (QApplication.translate( "pychemqt", "Purchase Cost"), self.C_adq.str) + os.linesep txt += "%-25s\t%s" % (QApplication.translate( "pychemqt", "Installed Cost"), self.C_inst.str) + os.linesep return txt @classmethod def propertiesEquipment(cls): list = [ (QApplication.translate("pychemqt", "Input Pressure"), "Pin", Pressure), (QApplication.translate("pychemqt", "Output Pressure"), "PoutCalculada", Pressure), (QApplication.translate("pychemqt", "Head"), "headCalculada", Length), (QApplication.translate("pychemqt", "Brake horsepower"), "P_freno", Power), (QApplication.translate("pychemqt", "Volumetric Flow"), "volflow", VolFlow), (QApplication.translate("pychemqt", "Power"), "power", Power), (QApplication.translate("pychemqt", "Efficiency"), "rendimientoCalculado", Dimensionless), (QApplication.translate("pychemqt", "Pump Type"), ("TEXT_BOMBA", "tipo_bomba"), str), (QApplication.translate("pychemqt", "Centrifuge Type"), ("TEXT_CENTRIFUGA", "tipo_centrifuga"), str), (QApplication.translate("pychemqt", "Material"), ("TEXT_MATERIAL", "material"), str), (QApplication.translate("pychemqt", "Motor Type"), ("TEXT_MOTOR", "motor"), str), (QApplication.translate("pychemqt", "Motor RPM"), ("TEXT_RPM", "rpm"), str), (QApplication.translate("pychemqt", "Pump Cost"), "C_bomba", Currency), (QApplication.translate("pychemqt", "Motor Cost"), "C_motor", Currency), (QApplication.translate("pychemqt", "Purchase Cost"), "C_adq", Currency), (QApplication.translate("pychemqt", "Installed Cost"), "C_inst", Currency) ] return list def datamap2xls(self): datamap = ( ("PoutCalculada", "value", "H15"), ("PoutCalculada", "unit", "I15"), ("Pin", "value", "H16"), ("Pin", "unit", "I16"), ) return datamap def export2pdf(self): bomba = pdf("Bomba") bomba.bomba(self) bomba.dibujar() os.system("evince datasheet.pdf") def export2xls(self): font0 = xlwt.Font() font0.bold = True font0.height = 300 print font0.height style0 = xlwt.XFStyle() style0.font = font0 style1 = xlwt.XFStyle() style1.num_format_str = 'D-MMM-YY' wb = xlwt.Workbook() ws = wb.add_sheet('A Test Sheet') ws.write(0, 0, 'Test', style0) ws.write(2, 0, 1) ws.write(2, 1, 1) ws.write(2, 2, xlwt.Formula("A3+B3")) wb.save('datasheet.xls') os.system("gnumeric datasheet.xls")
def calculo(self): self.entrada = self.kwargs["entrada"] self.LKsplit = unidades.Dimensionless(self.kwargs["LKsplit"]) self.HKsplit = unidades.Dimensionless(self.kwargs["HKsplit"]) self.RCalculada = unidades.Dimensionless(self.kwargs["R"]) self.R_Rmin = unidades.Dimensionless(self.kwargs["R_Rmin"]) if self.kwargs["Pd"]: self.Pd = unidades.Pressure(self.kwargs["Pd"]) else: self.Pd = self.entrada.P self.DeltaP = unidades.Pressure(self.kwargs["DeltaP"]) #Estimate splits of components b = [] d = [] for i, caudal_i in enumerate(self.entrada.caudalunitariomolar): if i == self.kwargs["LK"]: b.append(caudal_i * (1 - self.LKsplit)) d.append(caudal_i * self.LKsplit) elif i == self.kwargs["HK"]: d.append(caudal_i * (1 - self.HKsplit)) b.append(caudal_i * self.HKsplit) elif self.entrada.eos.Ki[i] > self.entrada.eos.Ki[ self.kwargs["LK"]]: b.append(0) d.append(caudal_i) elif self.entrada.eos.Ki[i] < self.entrada.eos.Ki[ self.kwargs["HK"]]: d.append(0) b.append(caudal_i) else: d.append(caudal_i * 0.5) b.append(caudal_i * 0.5) while True: bo = b do = d xt = [Q / sum(d) for Q in d] xb = [Q / sum(b) for Q in b] Qt = sum( [di * comp.M for di, comp in zip(d, self.entrada.componente)]) Qb = sum( [bi * comp.M for bi, comp in zip(b, self.entrada.componente)]) destilado = Corriente(T=self.entrada.T, P=self.Pd, caudalMasico=Qt, fraccionMolar=xt) residuo = Corriente(T=self.entrada.T, P=self.Pd, caudalMasico=Qb, fraccionMolar=xb) #TODO: Add algorithm to calculate Pd and condenser type fig 12.4 pag 230 #Fenske equation for Nmin alfam = (destilado.eos.Ki[self.kwargs["LK"]] / destilado.eos.Ki[self.kwargs["HK"]] * residuo.eos.Ki[self.kwargs["LK"]] / residuo.eos.Ki[self.kwargs["HK"]])**0.5 Nmin = log10( destilado.caudalunitariomolar[self.kwargs["LK"]] / destilado.caudalunitariomolar[self.kwargs["HK"]] * residuo.caudalunitariomolar[self.kwargs["HK"]] / residuo.caudalunitariomolar[self.kwargs["LK"]]) / log10(alfam) #Evaluación composición salidas b = [] d = [] for i in range(len(self.entrada.ids)): if i in [self.kwargs["LK"], self.kwargs["HK"]]: b.append(bo[i]) d.append(do[i]) else: alfa = (destilado.eos.Ki[i] / destilado.eos.Ki[self.kwargs["HK"]] * residuo.eos.Ki[i] / residuo.eos.Ki[self.kwargs["HK"]])**0.5 b.append(self.entrada.caudalunitariomolar[i] / (1 + do[self.kwargs["HK"]] / bo[self.kwargs["HK"]] * alfa**Nmin)) d.append(self.entrada.caudalunitariomolar[i] * do[self.kwargs["HK"]] / bo[self.kwargs["HK"]] * alfa**Nmin / (1 + do[self.kwargs["HK"]] / bo[self.kwargs["HK"]] * alfa**Nmin)) res = sum([ abs(inicial - final) for inicial, final in zip(bo, b) ]) + sum([abs(inicial - final) for inicial, final in zip(do, d)]) if res < 1e-10: self.Nmin = Nmin - self.kwargs["condenser"] + 1 break #Calculo de la razón de reflujo mínima, ecuación de Underwood alfa = self.entrada.eos.Ki[self.kwargs["LK"]] / self.entrada.eos.Ki[ self.kwargs["HK"]] self.Rmin = unidades.Dimensionless( abs( float(destilado.caudalmolar / self.entrada.caudalmolar * (destilado.fraccion[self.kwargs["LK"]] / self.entrada.Liquido.fraccion[self.kwargs["LK"]] - alfa * destilado.fraccion[self.kwargs["HK"]] / self.entrada.Liquido.fraccion[self.kwargs["HK"]]) / (alfa - 1)))) #Cálculo del número de etapas reales, ecuación de Gilliland if self.R_Rmin and not self.RCalculada: self.RCalculada = unidades.Dimensionless(self.R_Rmin * self.Rmin) X = (self.RCalculada - self.Rmin) / (self.RCalculada + 1) Y = 1 - exp((1 + 54.4 * X) / (11 + 117.2 * X) * (X - 1) / X**0.5) self.NTray = unidades.Dimensionless((Y + self.Nmin) / (1 - Y) - 1 - self.kwargs["condenser"]) #Cálculo del piso de la alimentación if self.kwargs["feed"]: #Ec. de Fenske alfa_b = residuo.eos.Ki[self.kwargs["LK"]] / residuo.eos.Ki[ self.kwargs["HK"]] alfa_d = destilado.eos.Ki[self.kwargs["LK"]] / destilado.eos.Ki[ self.kwargs["HK"]] alfa_f = self.entrada.eos.Ki[ self.kwargs["LK"]] / self.entrada.eos.Ki[self.kwargs["HK"]] ratio = log(destilado.fraccion[self.kwargs["LK"]] / self.entrada.fraccion[self.kwargs["LK"]] * self.entrada.fraccion[self.kwargs["HK"]] / destilado.fraccion[self.kwargs["HK"]]) / log( self.entrada.fraccion[self.kwargs["LK"]] / residuo.fraccion[self.kwargs["LK"]] * residuo.fraccion[self.kwargs["HK"]] / self.entrada.fraccion[self.kwargs["HK"]]) * log( (alfa_b * alfa_f)**0.5) / log( (alfa_d * alfa_f)**0.5) else: #Ec. de Kirkbride ratio = (self.entrada.fraccion[self.kwargs["HK"]] / self.entrada.fraccion[self.kwargs["LK"]] * residuo.fraccion[self.kwargs["LK"]]**2 / destilado.fraccion[self.kwargs["HK"]]**2 * residuo.caudalmolar / destilado.caudalmolar)**0.206 self.Ns = self.NTray / (ratio + 1) self.Nr = self.NTray - self.Ns self.N_feed = unidades.Dimensionless(self.Ns + 1) if self.kwargs["condenser"]: #Parcial Tout = destilado.eos._Dew_T() else: Tout = destilado.eos._Bubble_T() Tin = destilado.eos._Dew_T() SalidaDestilado = destilado.clone(T=Tout) #FIXME: o el ejemplo está mal planteado o este valor es ilógico ToutReboiler = residuo.eos._Bubble_T() ToutReboiler2 = residuo.eos._Dew_T() print((ToutReboiler, ToutReboiler2, Tin, Tout)) SalidaResiduo = residuo.clone(T=ToutReboiler) self.salida = [SalidaDestilado, SalidaResiduo] inCondenser = destilado.clone(T=Tin, P=self.entrada.P, split=self.RCalculada + 1) outCondenser = destilado.clone(T=Tout, P=self.entrada.P, split=self.RCalculada + 1) self.DutyCondenser = unidades.Power(outCondenser.h - inCondenser.h) self.DutyReboiler = unidades.Power(SalidaDestilado.h + SalidaResiduo.h - self.DutyCondenser - self.entrada.h) self.DestiladoT = SalidaDestilado.T self.DestiladoP = SalidaDestilado.P self.DestiladoMassFlow = SalidaDestilado.caudalmasico self.DestiladoMolarComposition = SalidaDestilado.fraccion self.ResiduoT = SalidaResiduo.T self.ResiduoP = SalidaResiduo.P self.ResiduoMassFlow = SalidaResiduo.caudalmasico self.ResiduoMolarComposition = SalidaResiduo.fraccion self.LKName = self.salida[0].componente[self.kwargs["LK"]].nombre self.HKName = self.salida[0].componente[self.kwargs["HK"]].nombre
def calculo(self): self.entrada=self.kwargs["entrada"] self.LKsplit=unidades.Dimensionless(self.kwargs["LKsplit"]) self.HKsplit=unidades.Dimensionless(self.kwargs["HKsplit"]) self.RCalculada=unidades.Dimensionless(self.kwargs["R"]) self.R_Rmin=unidades.Dimensionless(self.kwargs["R_Rmin"]) if self.kwargs["Pd"]: self.Pd=unidades.Pressure(self.kwargs["Pd"]) else: self.Pd=self.entrada.P self.DeltaP=unidades.Pressure(self.kwargs["DeltaP"]) #Estimate splits of components b=[] d=[] for i, caudal_i in enumerate(self.entrada.caudalunitariomolar): if i==self.kwargs["LK"]: b.append(caudal_i*(1-self.LKsplit)) d.append(caudal_i*self.LKsplit) elif i==self.kwargs["HK"]: d.append(caudal_i*(1-self.HKsplit)) b.append(caudal_i*self.HKsplit) elif self.entrada.eos.Ki[i]>self.entrada.eos.Ki[self.kwargs["LK"]]: b.append(0) d.append(caudal_i) elif self.entrada.eos.Ki[i]<self.entrada.eos.Ki[self.kwargs["HK"]]: d.append(0) b.append(caudal_i) else: d.append(caudal_i*0.5) b.append(caudal_i*0.5) while True: bo=b do=d xt=[Q/sum(d) for Q in d] xb=[Q/sum(b) for Q in b] Qt=sum([di*comp.M for di, comp in zip(d, self.entrada.componente)]) Qb=sum([bi*comp.M for bi, comp in zip(b, self.entrada.componente)]) destilado=Corriente(T=self.entrada.T, P=self.Pd, caudalMasico=Qt, fraccionMolar=xt) residuo=Corriente(T=self.entrada.T, P=self.Pd, caudalMasico=Qb, fraccionMolar=xb) #TODO: Add algorithm to calculate Pd and condenser type fig 12.4 pag 230 #Fenske equation for Nmin alfam=(destilado.eos.Ki[self.kwargs["LK"]]/destilado.eos.Ki[self.kwargs["HK"]]*residuo.eos.Ki[self.kwargs["LK"]]/residuo.eos.Ki[self.kwargs["HK"]])**0.5 Nmin=log10(destilado.caudalunitariomolar[self.kwargs["LK"]]/destilado.caudalunitariomolar[self.kwargs["HK"]] * residuo.caudalunitariomolar[self.kwargs["HK"]]/residuo.caudalunitariomolar[self.kwargs["LK"]]) / log10(alfam) #Evaluación composición salidas b=[] d=[] for i in range(len(self.entrada.ids)): if i in [self.kwargs["LK"], self.kwargs["HK"]]: b.append(bo[i]) d.append(do[i]) else: alfa=(destilado.eos.Ki[i]/destilado.eos.Ki[self.kwargs["HK"]]*residuo.eos.Ki[i]/residuo.eos.Ki[self.kwargs["HK"]])**0.5 b.append(self.entrada.caudalunitariomolar[i]/(1+do[self.kwargs["HK"]]/bo[self.kwargs["HK"]]*alfa**Nmin)) d.append(self.entrada.caudalunitariomolar[i]*do[self.kwargs["HK"]]/bo[self.kwargs["HK"]]*alfa**Nmin/(1+do[self.kwargs["HK"]]/bo[self.kwargs["HK"]]*alfa**Nmin)) res=sum([abs(inicial-final) for inicial, final in zip(bo, b)]) + sum([abs(inicial-final) for inicial, final in zip(do, d)]) if res<1e-10: self.Nmin=Nmin-self.kwargs["condenser"]+1 break #Calculo de la razón de reflujo mínima, ecuación de Underwood alfa=self.entrada.eos.Ki[self.kwargs["LK"]]/self.entrada.eos.Ki[self.kwargs["HK"]] self.Rmin=unidades.Dimensionless(abs(float(destilado.caudalmolar/self.entrada.caudalmolar*(destilado.fraccion[self.kwargs["LK"]]/self.entrada.Liquido.fraccion[self.kwargs["LK"]]-alfa*destilado.fraccion[self.kwargs["HK"]]/self.entrada.Liquido.fraccion[self.kwargs["HK"]])/(alfa-1)))) #Cálculo del número de etapas reales, ecuación de Gilliland if self.R_Rmin and not self.RCalculada: self.RCalculada=unidades.Dimensionless(self.R_Rmin*self.Rmin) X=(self.RCalculada-self.Rmin)/(self.RCalculada+1) Y=1-exp((1+54.4*X)/(11+117.2*X)*(X-1)/X**0.5) self.NTray=unidades.Dimensionless((Y+self.Nmin)/(1-Y)-1-self.kwargs["condenser"]) #Cálculo del piso de la alimentación if self.kwargs["feed"]: #Ec. de Fenske alfa_b=residuo.eos.Ki[self.kwargs["LK"]]/residuo.eos.Ki[self.kwargs["HK"]] alfa_d=destilado.eos.Ki[self.kwargs["LK"]]/destilado.eos.Ki[self.kwargs["HK"]] alfa_f=self.entrada.eos.Ki[self.kwargs["LK"]]/self.entrada.eos.Ki[self.kwargs["HK"]] ratio=log(destilado.fraccion[self.kwargs["LK"]]/self.entrada.fraccion[self.kwargs["LK"]]*self.entrada.fraccion[self.kwargs["HK"]]/destilado.fraccion[self.kwargs["HK"]])/log(self.entrada.fraccion[self.kwargs["LK"]]/residuo.fraccion[self.kwargs["LK"]]*residuo.fraccion[self.kwargs["HK"]]/self.entrada.fraccion[self.kwargs["HK"]])*log((alfa_b*alfa_f)**0.5)/log((alfa_d*alfa_f)**0.5) else: #Ec. de Kirkbride ratio=(self.entrada.fraccion[self.kwargs["HK"]]/self.entrada.fraccion[self.kwargs["LK"]]*residuo.fraccion[self.kwargs["LK"]]**2/destilado.fraccion[self.kwargs["HK"]]**2*residuo.caudalmolar/destilado.caudalmolar)**0.206 self.Ns=self.NTray/(ratio+1) self.Nr=self.NTray-self.Ns self.N_feed=unidades.Dimensionless(self.Ns+1) if self.kwargs["condenser"]: #Parcial Tout=destilado.eos._Dew_T() else: Tout=destilado.eos._Bubble_T() Tin=destilado.eos._Dew_T() SalidaDestilado=destilado.clone(T=Tout) #FIXME: o el ejemplo está mal planteado o este valor es ilógico ToutReboiler=residuo.eos._Bubble_T() ToutReboiler2=residuo.eos._Dew_T() print ToutReboiler, ToutReboiler2, Tin, Tout SalidaResiduo=residuo.clone(T=ToutReboiler) self.salida=[SalidaDestilado, SalidaResiduo] inCondenser=destilado.clone(T=Tin, P=self.entrada.P, split=self.RCalculada+1) outCondenser=destilado.clone(T=Tout, P=self.entrada.P, split=self.RCalculada+1) self.DutyCondenser=unidades.Power(outCondenser.h-inCondenser.h) self.DutyReboiler=unidades.Power(SalidaDestilado.h+SalidaResiduo.h-self.DutyCondenser-self.entrada.h) self.DestiladoT=SalidaDestilado.T self.DestiladoP=SalidaDestilado.P self.DestiladoMassFlow=SalidaDestilado.caudalmasico self.DestiladoMolarComposition=SalidaDestilado.fraccion self.ResiduoT=SalidaResiduo.T self.ResiduoP=SalidaResiduo.P self.ResiduoMassFlow=SalidaResiduo.caudalmasico self.ResiduoMolarComposition=SalidaResiduo.fraccion self.LKName=self.salida[0].componente[self.kwargs["LK"]].nombre self.HKName=self.salida[0].componente[self.kwargs["HK"]].nombre