Diseño de la red de intercambiadores

El último ejemplo que vamos a ver es el del diseño de la red de intercambiadores. PinchPython es capaz de diseñar la red de intercambiadores usando el método pinch. También realiza un prediseño de cada cambiador, y con la información obtenida es posible dibujar los perfiles de cada intercambiador (como hace por ejemplo el programa GnuPinch).

El programa para diseñar la red es similar al programa de la sección anterior. Comenzamos definiendo las corrientes, y averiguando la temperatura del punto pinch:

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
from PinchPython import *

c1 = Corriente()
c2 = Corriente()
c3 = Corriente()
c4 = Corriente()
vapor = Corriente()
agua = Corriente()

c1.setT0(20.)
c1.setTf(180.)
c1.setMCP(0.2)
c1.setCoeficientePelicula(0.0006)

c2.setT0(250.)
c2.setTf(40.)
c2.setMCP(0.15)
c2.setCoeficientePelicula(0.0010)

c3.setT0(140.)
c3.setTf(230.)
c3.setMCP(0.3)
c3.setCoeficientePelicula(0.0008)

c4.setT0(200.)
c4.setTf(80.)
c4.setMCP(0.25)
c4.setCoeficientePelicula(0.0008)

vapor.setT0(240.)
vapor.setTf(239.)
vapor.setMCP(7.50)
vapor.setCoeficientePelicula(0.0030)

agua.setT0(20.)
agua.setTf(30.)
agua.setMCP(1.)
agua.setCoeficientePelicula(0.0010)

corrientesFrias = [c1, c3]
corrientesCalientes = [c2, c4]

cFria = CurvaCompuesta(corrientesFrias)
cCaliente = CurvaCompuesta(corrientesCalientes)

ATMin = 10.0  # ºC

tabla = TablaDelProblema(cFria,cCaliente,10.0)
tPinch = tabla.getTemperaturaModificadaPinch()

print 'T Pinch = '+str(tPinch)+' ºC'

Ahora vamos a escribir una pequeña tabla que nos muestre el número de identificación de cada corriente. Así, cuando escribamos la tabla del resultado del diseño de la red podremos identificar qué corriente pasa por cada unidad.

print "Corrientes originales:"
print "c1 es "+str(c1.getIdNum())
print "c2 es "+str(c2.getIdNum())
print "c3 es "+str(c3.getIdNum())
print "c4 es "+str(c4.getIdNum())

Ahora simplemente creamos el diseño de la red:

diseno = DisenoRedIntercambiadores(corrientesFrias,corrientesCalientes,tPinch,ATMin)

Y empezamos a generar una tabla con los resultados. En cada fila pondremos los datos de cada unidad. Si es un intercambiador de proceso, pondremos el duty, el área, el número de identificación de la corriente caliente y el número de identificación de la corriente fría. Empecemos por el lado caliente:

print "Duty lado caliente - Area - Id Caliente - Id Fria"
for c in diseno.getListaCambiadoresLadoCaliente():
        texto = ""
        if c.getTipo() is 'Intercambiador':
                texto = str(c.getDuty())+'\t'
                texto += str(c.getArea())+' m2\t'
                texto += str(c.getCorrienteCaliente().getVectorAncestros()[0])
                texto += '\t'+str(c.getCorrienteFria().getVectorAncestros()[0])         
        else:
                texto = str(c.getDuty())
        
        print texto

Si ejecutamos ahora el programa obtendremos los resultados para la subred por encima del pinch:

T Pinch=145.0
Corrientes originales:
c1 es 1
c2 es 2
c3 es 3
c4 es 4
Duty lado caliente - Area - Id Caliente - Id Fria
12.5    2273.00926339 m2        4       3
8.0     1355.67657662 m2        2       1
7.0     493.349068266 m2        2       3
7.5

Observamos que por encima del pinch hay cuatro unidades, una de las cuales corresponde a servicios auxiliares. Podemos corroborar los datos mostrados con la red de la figura [*].

El vector de ancestros de una corriente es un vector que contiene los números de identificación de todas las corrientes padres de esa corriente. Cada vez que se divide una corriente se generan dos nuevas, por lo que su identificación cambia. Sin embargo el número de identificación de la corriente que generó a todas las corrientes divididas no se pierde, y es el primer elemento del vector de ancestros. Así es fácil identificar qué corriente pasa por cada intercambiador.

Antes de seguir para mostrar los resultados por debajo del pinch, vamos a cambiar la forma en presentar los resultados. Por cada cambiador, vamos a mostrar:

Vamos a aprovechar el bucle para mostrar todos los cambiadores de la red de intercambiadores. Este código sustituye al mostrado en el bloque anterior

lista_cambiadores = diseno.getListaCambiadoresLadoCaliente()
lista_cambiadores += diseno.getListaCambiadoresLadoFrio()
for c in lista_cambiadores:
        if c.getTipo() is 'Intercambiador':
                # Intercambiador de proceso
                
                # Datos del intercambiador
                duty = c.getDuty()
                area = c.getArea()
                mldt = c.getLMTD()
                th1 = c.getTH1()
                th0 = c.getTH0()
                tc0 = c.getTC0()
                tc1 = c.getTC1()
                id_h = c.getCorrienteCaliente().getVectorAncestros()[0]
                id_c = c.getCorrienteFria().getVectorAncestros()[0]
                mcp_h = duty/(th0-th1)
                mcp_c = duty/(tc1-tc0)
                U = c.getU()*1e6

                # Presentación de resultados
                print "---------------------------------"
                print "Cambiador de proceso"
                print "---------------------------------"
                print "Lado\tT entrada (ºC)\tT salida (ºC)\tId. Num\tMCP (MW/ºC)\tDividida"

                # Primero el lado caliente
                texto = "Caliente\t"+str(th0)+"\t"+str(th1)+"\t"
                texto += str(id_h)+"\t"+str(mcp_h)+"\t"

                # ¿Corriente dividida?
                if len(c.getCorrienteCaliente().getVectorAncestros()) == 1:
                        texto += "No"
                else:
                        texto += "Sí"

                print texto

                # Después el lado frío
                texto = "Frío\t"+str(tc0)+"\t"+str(tc1)+"\t"
                texto += str(id_c)+"\t"+str(mcp_c)+"\t"

                # ¿Corriente dividida?
                if len(c.getCorrienteFria().getVectorAncestros()) == 1:
                        texto += "No"
                else:
                        texto += "Sí"

                print texto

                print
                print "Duty = "+str(duty)+" MW"
                print "Area = "+str(area)+" m2"
                print "U = "+str(U)+" W/m2 ºC"
                print "MLDT = "+str(mldt)+" ºC"

Este código presenta un resumen detallado de cada cambiador del proceso por encima del pinch. Veamos ahora el código para los cambiadores auxiliares, por debajo del pinch:

        elif c.getCorriente().getTipo() is 'Caliente':
                # Cambiador auxiliar por debajo del pinch

                # Usaremos el agua como corriente auxiliar
                c.FijarCorrienteAuxiliar(agua)

                # Datos del intercambiador
                duty = c.getDuty()
                area = c.getArea()
                mdlt = c.getLMTD()
                th1 = c.getTH1()
                th0 = c.getTH0()
                tc0 = c.getTC0()
                tc1 = c.getTC1()
                id_h = vapor.getVectorAncestros()[0]
                id_c = c.getCorriente().getVectorAncestros()[0]
                mcp_h = duty/(th0-th1)
                mcp_c = duty/(tc1-tc0)
                U = c.getU()*1e6

                # Presentación de resultados
                print "---------------------------------"
                print "Cambiador auxiliar"
                print "---------------------------------"
                print "Lado\tT entrada (ºC)\tT salida (ºC)\tId. Num\tMCP (MW/ºC)\tDividida"

                # Primero el lado caliente
                texto = "Caliente\t"+str(th0)+"\t"+str(th1)+"\t"
                texto += str(id_h)+"\t"+str(mcp_h)+"\t"

                # ¿Corriente dividida?
                if len(c.getCorriente().getVectorAncestros()) == 1:
                        texto += "No"
                else:
                        texto += "Sí"

                print texto

                # Después el lado frío
                texto = "Frío\t"+str(tc0)+"\t"+str(tc1)+"\t"
                texto += str(id_c)+"\t"+str(mcp_c)+"\t"

                # ¿Corriente dividida?
                if len(agua.getVectorAncestros()) == 1:
                        texto += "No"
                else:
                        texto += "Sí"

                print texto

                print
                print "Duty = "+str(duty)+" MW"
                print "Area = "+str(area)+" m2"
                print "U = "+str(U)+" W/m2 ºC"
                print "MLDT = "+str(mdlt)+" ºC"

Como vemos, hemos elegido la corriente de agua para todos y cada uno de los cambiadores auxiliares. En este caso es indiferente, puesto que sólo hay un cambiador auxiliar. En otros casos, no es posible unir directamente una corriente de servicios auxiliares con un cambiador.

Por último, los cambiadores auxiliares por encima del pinch. Es similar al código anterior, pero sustituyendo el vapor por el agua, y cambiando la corriente fría por la caliente y viceversa:

        else:
                # Cambiador auxiliar por encima del pinch

                # Usaremos el vapor como corriente auxiliar
                c.FijarCorrienteAuxiliar(vapor)

                # Datos del intercambiador
                duty = c.getDuty()
                area = c.getArea()
                mdlt = c.getLMTD()
                th1 = c.getTH1()
                th0 = c.getTH0()
                tc0 = c.getTC0()
                tc1 = c.getTC1()
                id_h = vapor.getVectorAncestros()[0]
                id_c = c.getCorriente().getVectorAncestros()[0]
                mcp_h = duty/(th0-th1)
                mcp_c = duty/(tc1-tc0)
                U = c.getU()*1e6

                # Presentación de resultados
                print "---------------------------------"
                print "Cambiador auxiliar"
                print "---------------------------------"
                print "Lado\tT entrada (ºC)\tT salida (ºC)\tId. Num\tMCP (MW/ºC)\tDividida"

                # Primero el lado caliente
                texto = "Caliente\t"+str(th0)+"\t"+str(th1)+"\t"
                texto += str(id_h)+"\t"+str(mcp_h)+"\t"

                # ¿Corriente dividida?
                if len(vapor.getVectorAncestros()) == 1:
                        texto += "No"
                else:
                        texto += "Sí"

                print texto

                # Después el lado frío
                texto = "Frío\t"+str(tc0)+"\t"+str(tc1)+"\t"
                texto += str(id_c)+"\t"+str(mcp_c)+"\t"

                # ¿Corriente dividida?
                if len(c.getCorriente().getVectorAncestros()) == 1:
                        texto += "No"
                else:
                        texto += "Sí"

                print texto

                print
                print "Duty = "+str(duty)+" MW"
                print "Area = "+str(area)+" m2"
                print "U = "+str(U)+" W/m2 ºC"
                print "MLDT = "+str(mdlt)+" ºC"

Veamos cómo se muestran ahora los resultados:

T Pinch=145.0
Corrientes originales:
c1 es 1
c2 es 2
c3 es 3
c4 es 4
vapor es 5
agua es 6
---------------------------------
Cambiador de proceso
---------------------------------
Lado           T entrada (ºC)  T salida (ºC)   Id. Num     MCP (MW/ºC)     Dividida
Caliente        200.0           150.0            4            0.25            No
Frío            140.0           181.666666667    3            0.3             No
                                                                                                                             
Duty = 12.5 MW
Area = 2273.00926339 m2
U = 400.0 W/m2 ºC
MLDT = 13.7482941682 ºC
---------------------------------
Cambiador de proceso
---------------------------------
Lado       T entrada (ºC)    T salida (ºC)   Id. Num    MCP (MW/ºC)     Dividida
Caliente    203.333333333     150.0           2         0.15               No
Frío        140.0             180.0           1         0.2                No
                                                                                                                             
Duty = 8.0 MW
Area = 1355.67657662 m2
U = 375.0 W/m2 ºC
MLDT = 15.7363000153 ºC
---------------------------------
Cambiador de proceso
---------------------------------
Lado         T entrada (ºC)    T salida (ºC)    Id. Num    MCP (MW/ºC)     Dividida
Caliente      250.0             203.333333333    2          0.15             No
Frío          181.666666667     205.0            3          0.3              No
                                                                                                                             
Duty = 7.0 MW
Area = 493.349068266 m2
U = 444.444444444 W/m2 ºC
MLDT = 31.9246574344 ºC
---------------------------------
Cambiador auxiliar
---------------------------------
Lado           T entrada (ºC)  T salida (ºC)   Id. Num   MCP (MW/ºC)     Dividida
Caliente        240.0           239.0             5       7.5               No
Frío            205.0           230.0             3       0.3               No
 
Duty = 7.5 MW
Area = 605.513885438 m2
U = 631.578947368 W/m2 ºC
MLDT = 19.611441266 ºC
---------------------------------
Cambiador de proceso
---------------------------------
Lado       T entrada (ºC)  T salida (ºC)   Id. Num   MCP (MW/ºC)  Dividida
Caliente    150.0           80.0             4        0.25           No
Frío         52.5           140.0            1        0.2            No
 
Duty = 17.5 MW
Area = 2950.50265906 m2
U = 342.857142857 W/m2 ºC
MLDT = 17.299312207 ºC
---------------------------------
Cambiador de proceso
---------------------------------
Lado         T entrada (ºC)  T salida (ºC)   Id. Num   MCP (MW/ºC)  Dividida
Caliente      150.0           106.666666667     2       0.15          No
Frío           20.0            52.5             1       0.2           No
 
Duty = 6.5 MW
Area = 188.45285705 m2
U = 375.0 W/m2 ºC
MLDT = 91.9770260035 ºC
---------------------------------
Cambiador auxiliar
---------------------------------
Lado        T entrada (ºC)  T salida (ºC)   Id. Num   MCP (MW/ºC)  Dividida
Caliente     106.666666667   40.0              5       0.15          No
Frío          20.0           30.0              2       1.0           No
 
Duty = 10.0 MW
Area = 474.259322365 m2
U = 500.0 W/m2 ºC
MLDT = 42.1710213312 ºC

Las tabulaciones se han retocado algo para que el resultado sea más legible. Podemos observar que tenemos datos suficientes para diseñar tanto la subred por encima del pinch, como cada una de las unidades que forman esta subred.

2004-05-30