Example #1
0
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")
Example #2
0
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")
Example #3
0
    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
Example #4
0
    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