Torres de absorción rellenas - Funciones JavaScript
En este capítulo, por conveniencia, las funciones JavaScript, tienen los mismos nombres que las funciones HP equivalentes.
Flujos de entrada y salida en torres rellenas
La función que calcula los flujos y composiciones de salida, contando con los flujos y composiciones de entrada (L2, x2, V1, y1) y el porcentaje de absorción (pa), se denomina abrc1:
function abrc1({L2, x2, V1, y1, pa}={}) {
const B = L2*(1-x2);
const C = V1*(1-y1);
const A = B*(x2/(1-x2))+C*(y1/(1-y1));
const V2y2 = V1*y1*(1-pa/100);
const V2 = C+V2y2;
const y2 = V2y2/V2;
const D = (A-C*(y2/(1-y2)))/B;
const x1 = D/(1+D);
const L1 = B/(1-x1);
return {L1, x1, V2, y2};
}
Para resolver, con esta función, el ejemplo 5.1.1 del texto, se procede de la siguiente forma:
Con los datos conocidos se calcula el porcentaje de absorción (siguiendo los pasos explicados en el texto):
C = (V1*(1-y1)).round(6)
V2 = (C/(1-y2)).round(6)
pa = ((V1*y1-V2*y2)/(V1*y1)*100).round(6)
Finalmente, con todos los datos conocidos, se calculan las composiciones y flujos de salida:
round(abrc1({L2, x2, V1, y1, pa}),6)
Coeficientes de transferencia de masa
Coeficientes individuales ideales
El cálculo de las fracciones molares en la interfaz gas-líquido (xi, yi), así como los flujos molares superficiales (Nax, Nay), ha sido programada en la función xiyi1:
function xiyi1({x, y, kpx, kpy, fx, fy}={}) {
let yi;
function f(xi) {
yi = fx(xi);
return kpx/kpy+(y-yi)/(x-xi);
}
const xi = f.refa({xi:x+1e-5, xf: fy(y)-1e-5});
Nax = kpx*(xi-x);
Nay = kpy*(y-yi);
return {xi, yi, Nax, Nay}
}
Esta función recibe las fracciones molares (x, y), los coeficientes individuales ideales (kpx, kpy) y las funciones de equilibrio (fx, fy). Se les recuerda que el código de la función está disponible también en las referencias de las funciones, al final del capítulo, pero también puede ser recuperada en cualquier instrucción de la calculadora escribiendo el nombre de la función, como se muestra a continuación:
xiyi1
Para resolver, con esta función, el ejemplo 5.3.1.1 el texto, se procede de la siguiente forma:
Con los datos de equilibrio conocidos, se crean las funciones de equilibrio:
x = 0.1; y = 0.38; kpx = 1.967e-3, kpy = 1.465e-3;
Finalmente, con todos los datos conocidos, se calculan las fracciones molares en la interfaz gas-líquido y los flujos molares (en kmol/s*m2) con xiyi1:
xiyi1({x, y, kpx, kpy, fx, fy})
Coeficientes individuales reales
Cuando en lugar de los coeficientes individuales ideales, se cuenta con los coeficientes individuales reales, se emplea igualmente el programa xiyi1, sólo que en lugar de enviar a la función los coeficientes ideales, se envía los coeficientes reales.
Así, el ejemplo 5.3.2.1 del texto se resuelve con las siguientes instrucciones:
Cálculo de los coeficientes individuales reales a partir de los ideales
El programa que realiza el cálculo se denomina xiyi2, el cual recibe las fracciones molares en las fases gaseosa y líquida (x, y), los coeficientes individuales ideales (kpx, kpy) y las funciones de equilibrio (fx y fy):
function xiyi2({x, y, kpx, kpy, fx, fy}={}) {
// Función de la fracción molar en el líquido en la interfaz gas-líquido
let yi, xim, yim, kx, ky;
function fxi(xi) {
yi = fx(xi);
xim = ((1-x)-(1-xi))/Math.log((1-x)/(1-xi));
yim = ((1-yi)-(1-y))/Math.log((1-yi)/(1-y));
kx = kpx/xim;
ky = kpy/yim;
return kx/ky+(y-yi)/(x-xi);
}
// Resolución de la función "fxi"
const xi = fxi.refa({xi:x+1e-5, xf:fy(y)-1e-5});
// Flujos de soluto
const Nax = kx*(xi-x);
const Nay = ky*(y-yi);
return {xi, yi, xim, yim, kx, ky, Nax, Nay};
}
Así, para resolver el ejemplo 5.3.3.1 del texto, se escriben las instrucciones:
Coeficientes globales ideales de transferencia de masa
Las funciones JavaScript equivalentes a las funciones Kx1 y Ky1 de la calculadora HP, son:
function Kx1({y, xi, yi, kpx, kpy, xa}={}) {
const m = (y-yi)/(xa-xi);
return 1/(1/(m*kpy)+1/kpx);
}
function Ky1({x, xi, yi, kpx, kpy, ya}={}) {
const m = (yi-ya)/(xi-x);
return 1/(1/kpy+m/kpx);
}
Empleando estas funciones (y las elaboradas previamente) el ejemplo 5.3.4.1, se resuelve con la siguiente función inmediatamente invocada (función IIFE):
Para resolver, con esta función, el ejemplo 5.4.1.9 (con los datos del ejemplo 5.4.1.1, con excepción del coeficiente global ideal KPx), se escribe la instrucción:
Kpx = 0.026;
zabKxi({L2, x2, L1, x1, y1, y2, Kpx, fy, S})
La función JavaScript equivalente a la función zabKx de la HP, es:
Para resolver, con esta función, el ejemplo 5.4.1.11 (con los datos del ejercicio 5.4.1.1, con excepción del coeficiente global Kx), se escribe la instrucción:
Kx = 0.0263;
zabKx({L2, x2, L1, x1, y1, y2, Kx, fy, S})
La función JavaScript equivalente a la función zabKyi de la HP, es:
function zabKyi({V1, y1, V2, y2, x2, x1, Kpy, fx, S}={}) {
const V = (V1+V2)/2;
const HOG = V/(Kpy*S);
const ya1 = fx(x1);
const ya2 = fx(x2);
const yam1 = ((1-ya1)-(1-y1))/Math.log((1-ya1)/(1-y1));
const yam2 = ((1-ya2)-(1-y2))/Math.log((1-ya2)/(1-y2));
const yma = ((y1-ya1)-(y2-ya2))/Math.log((y1-ya1)/(y2-ya2));
const ym = (yam1/(1-y1)+yam2/(1-y2))/2;
const NOG = ym*(y1-y2)/yma;
const z = HOG*NOG;
return {HOG, NOG, z};
}
Para resolver, con esta función, el ejemplo 5.4.1.13 (con los datos del ejercicio 5.4.1.1, con excepción del coeficiente global ideal Kpy), se escribe la instrucción:
Kpy = 0.02178;
zabKyi({V1, y1, V2, y2, x2, x1, Kpy, fx, S})
La función JavaScript equivalente a la función zabKy de la HP, es:
function zabKy({V1, y1, V2, y2, x2, x1, Ky, fx, S}={}) {
const ya1 = fx(x1);
const ya2 = fx(x2);
const yam1 = ((1-ya1)-(1-y1))/Math.log((1-ya1)/(1-y1));
const yam2 = ((1-ya2)-(1-y2))/Math.log((1-ya2)/(1-y2));
const yma = ((y1-ya1)-(y2-ya2))/Math.log((y1-ya1)/(y2-ya2));
const Vm = (V1/yam1+V2/yam2)/2;
const HOG = Vm/(Ky*S);
const ym = (yam1/(1-y1)+yam2/(1-y2))/2;
const NOG = ym*(y1-y2)/yma;
const z = HOG*NOG;
return {HOG, NOG, z};
}
Para resolver, con esta función, el ejemplo 5.4.1.15 (con los datos del ejercicio 5.4.1.1, con excepción del coeficiente global Ky), se escribe la instrucción:
Ky = 0.02199;
zabKy({V1, y1, V2, y2, x2, x1, Ky, fx, S})
Mezclas gaseosas concentradas
El método JavaScript equivalente a la función Trapt de la HP, para el cálculo de la integral a partir de datos tabulados, se denomina trapecio, el cual se llama desde la tabla que contiene los datos conocidos (filas x-y) a integrar.
Array.prototype.trapecio = function({a, b}={}) {
if (this.length<2) throw "trapecio: la tabla debe tener dos filas: datos 'x' y datos 'y'";
let [x, y] = [this[0].slice(), this[1].slice()];
if (x.length != y.length) throw "trapecio: las dos filas deben tener el mismo número de elementos."
if (x.length<2) throw "trapecio: La tabla debe tener por lo menos 2 puntos";
// Función local de interpolación lineal
const inLin = (xc,i,j) => {
const b = (y[i]-y[j])/(x[i]-x[j]);
const a = y[i]-b*x[i];
return a+b*xc;
};
// Si se ha mandado el límite inferior de integración
if (a!=undefined) {
// Y el límite es menor al menor valor tabulado, se extrapola el punto y se añade a los datos
if (a<x[0]) {
let yc = inLin(a,0,1);
x.unshift(a);
y.unshift(yc);
// Si no corresponde a uno de los puntos tabulados se interpola el punto, se eliminan los puntos previos y se añade al principio el punto interpolado
} else if (x.indexOf(a)<0) {
let j = x.findIndex(e => e>a);
if (j<0 || j>x.length-1) throw "trapecio: el límite inferior debe ser menor al último punto tabulado"
let yc = inLin(a,j-1,j);
x.splice(0,j); x.unshift(a);
y.splice(0,j); y.unshift(yc);
// Si es uno de los puntos tabulados, se eliminan los puntos previos
} else {
let i = x.indexOf(a);
x.splice(0,i);
y.splice(0,i);
}
}
// Si se ha mandado el límite superior de integración
if (b!=undefined) {
// Y el límite es mayor al mayor valor tabulado, se extrapola el punto y se añade a los datos
if (b>x[x.length-1]) {
let j = x.length-1;
let yc = inLin(b,j-1,j)
x.push(b);
y.push(yc);
// Si no corresponde a uno de los puntos tabulados se interpola el punto, se eliminan los puntos posteriores y se añade al filan el punto interpolado
} else if (x.indexOf(b)<0) {
let j = x.findIndex(e => e>b);
if (j<0 || j<1) throw "trapecio: el límite superior debe ser mayor al primer punto tabulado"
let yc = inLin(b,j-1,j);
x.splice(j); x.push(b);
y.splice(j); y.push(yc);
// Si es uno de los puntos tabulados, se eliminan los puntos posteriores
} else {
let k = x.indexOf(b);
x.splice(k+1);
y.splice(k+1);
}
}
// Se calcula la integral con el método del trapecio
let s = 0;
for (let i=0; i<x.length-1; i++) {
s += (x[i+1]-x[i])/2*(y[i]+y[i+1]);
}
return s;
};
Sin embargo, como se puede ver en el código, el método implementado en JavaScript no sólo integra todos los datos de la tabla (como ocurre con la versión HP), sino que permite integrar desde un valor intermedio (existente o no) hasta otro valor intermedio (existente o no) así como desde un valor anterior o posterior a los datos tabulados. El cálculo de la integral propiamente (que es lo único que se calcula en la versión HP), está programado en el último bloque del método.
El método JavaScript equivalente a la función Simpt de la Hp, se denomina simpson y al igual que en el método del trapecio, debe ser llamado desde la tabla con los datos conocidos (filas x-y):
Array.prototype.simpson = function({a, b}={}) {
if (this.length<2) throw "simpson: la tabla debe tener dos filas: datos 'x' y datos 'y'";
let [x, y] = [this[0].slice(), this[1].slice()];
if (x.length != y.length) throw "simpson: las dos filas deben tener el mismo número de elementos."
if (x.length<3) throw "simpson: La tabla debe tener por lo menos 3 puntos";
// Cálculo de los coeficientes de la ecuación cuadrática
const coeficientes = (i,j,k) => {
const a = ((y[i]-y[k])*(x[i]-x[j])-(y[i]-y[j])*(x[i]-x[k]))/
((x[i]**2-x[k]**2)*(x[i]-x[j])-(x[i]**2-x[j]**2)*(x[i]-x[k]));
const b = ((y[i]-y[j])-a*(x[i]**2-x[j]**2))/(x[i]-x[j]);
const c = y[i]-a*x[i]**2-b*x[i];
return [a,b,c];
};
// Cálculo del área debajo de la curva cuadrática
const area = (a,b,c,i,k) => a/3*(x[k]**3-x[i]**3)+b/2*(x[k]**2-x[i]**2)+c*(x[k]-x[i]);
// Si se ha mandado el límite inferior de integración
if (a!=undefined) {
// Y el límite es menor al menor valor tabulado, se extrapola el punto y se añade a los datos
if (a<x[0]) {
const [ca,cb,cc] = coeficientes(0,1,2);
x.unshift(a);
y.unshift(ca*a**2+cb*a+cc);
// Si no corresponde a uno de los puntos tabulados se interpola el punto, se eliminan los puntos previos y se añade al principio el punto interpolado
} else if (x.indexOf(a)<0) {
let j = x.findIndex(e => e>a);
if (j<0 || j>x.length-2) throw "simpson: el límite inferior debe ser menor al penúltimo punto tabulado"
const [ca,cb,cc] = coeficientes(j-1,j,j+1);
x.splice(0,j); x.unshift(a);
y.splice(0,j); y.unshift(ca*a**2+cb*a+cc);
// Si es uno de los puntos tabulados, se eliminan los puntos previos
} else {
let i = x.indexOf(a);
x.splice(0,i);
y.splice(0,i);
}
}
// Si se ha mandado el límite superior de integración
if (b!=undefined) {
// Y el límite es mayor al mayor valor tabulado, se extrapola el punto y se añade a los datos
if (b>x[x.length-1]) {
let k = x.length-1;
const [ca,cb,cc] = coeficientes(k-2,k-1,k);
x.push(b);
y.push(ca*b**2+cb*b+cc);
// Si no corresponde a uno de los puntos tabulados se interpola el punto, se eliminan los puntos posteriores y se añade al filan el punto interpolado
} else if (x.indexOf(b)<0) {
let j = x.findIndex(e => e>b);
if (j<0 || j<2) throw "simpson: el límite superior debe ser mayor al segundo punto tabulado"
const [ca,cb,cc] = coeficientes(j-2,j-1,j);
x.splice(j); x.push(b);
y.splice(j); y.push(ca*b**2+cb*b+cc);
// Si es uno de los puntos tabulados, se eliminan los puntos posteriores
} else {
let k = x.indexOf(b);
x.splice(k+1);
y.splice(k+1);
}
}
// Se calcula la integral con el método de Simpson
let s=0, i=0, n=(x.length-1).quot(2);
if (x.length%2===0) {
const [a,b,c] = coeficientes(0,1,2);
s += area(a,b,c,0,1);
i++;
}
for (let l=0; l<n; l++) {
const [a,b,c] = coeficientes(i,i+1,i+2);
s += area(a,b,c,i,i+2);
i+=2;
}
return s;
};
Al igual que el método del trapecio, el método de Sinpson permite integrar entre valores intermedios e inclusive entre valores anteriores y posteriores a los datos tabulados. La integración propiamente está programa en el último bloque de instrucciones del método.
Para integrar entre 2.5 y 7.2 (tanto con trapecio como con Simpson, se escribe:
[vx, vy].trapecio({a:2.5, b:7.2}).round(6)
[vx, vy].simpson({a:2.5, b:7.2}).round(6)
Con lo que se obtienen los mismos resultados que con Trapt y Simpt, sólo que, con los métodos trapecio y simpson, no es necesario recortar la tabla hasta los límites de integración, sino que se emplea la tabla completa y se mandan los límites de integración.
Para integrar desde el límite inicial hasta el límite final de la tabla, simplemente no se mandan los límites de integración:
[vx, vy].trapecio().round(6)
[vx, vy].simpson().round(6)
Para integrar entre valores intermedios no tabulados (interpolados), simplemente se escriben esos límites:
[vx, vy].trapecio({a:2.9, b:7.1}).round(6)
[vx, vy].simpson({a:2.9, b:7.1}).round(6)
Igualmente, para integrar entre valores anteriores y/o posteriores a los datos tabulados (extrapolación), simplemente se escriben los límites (por supuesto al tratarse de una extrapolación, no se puede garantizar la exactitud de los resultados):
[vx, vy].trapecio({a:1.8, b:7.6}).round(6)
[vx, vy].simpson({a:1.8, b:7.6}).round(6)
La función JavaScript equivalente a la función abkxi, es:
function abkxi({x2, L1, x1, V1, y1, fkpxkpy, fx, fy, S}={}) {
const B = L1*(1-x1);
const C = V1*(1-y1);
const D1 = B*x1/(1-x1)-C*y1/(1-y1);
const fkxi = x => {
const D2 = (B*x/(1-x)-D1)/C;
const y = D2/(1+D2);
const L = B/(1-x);
const V = C/(1-y);
const {kpx, kpy} = fkpxkpy({L, x, V, y, S});
const {xi, xim} = xiyi2({x, y, kpx, kpy, fx, fy});
return xim*L/(kpx*S*(1-x)*(xi-x));
};
return fkxi.simpson({a:x2, b:x1, n:10});
}
Así, para resolver el ejemplo 5.4.2.1 con esta función, se procede de la siguiente forma:
Finalmente, con todos los datos disponibles, se llama a la función abkxi, con lo que se obtiene la altura de la torre de absorción:
abkxi({x2, L1, x1, V1, y1, fkpxkpy, fx, fy, S})
La función JavaScript equivalente a la función abkx de la HP, es:
function abkx({x2, L1, x1, V1, y1, fkxky, fx, fy, S}={}) {
const B = L1*(1-x1);
const C = V1*(1-y1);
const D1 = B*x1/(1-x1)-C*y1/(1-y1);
const fkxi = x => {
const D2 = (B*x/(1-x)-D1)/C;
const y = D2/(1+D2);
const L = B/(1-x);
const V = C/(1-y);
const {kx, ky} = fkxky({L, x, V, y, S});
const {xi} = xiyi1({x, y, kpx:kx, kpy:ky, fx, fy});
return L/(kx*S*(1-x)*(xi-x));
};
return fkxi.simpson({a:x2, b:x1, n:10});
}
Para resolver, con esta función, el ejemplo 5.4.2.3, con los mismos datos que el ejemplo 5.4.2.1, con excepción del cálculo de los coeficientes de transferencia de masa individuales, que ahora se calculan con:
function fkxky({L, x, V, y, S}={}) {
const Gx = (L*(1-x)*18.02+L*x*64.1)/S;
const Gy = (V*(1-y)*28.97+V*y*64.1)/S
const kx = 0.159*Gx**0.82;
const ky = 0.0599*Gy**0.7*Gx**0.25;
return {kx, ky};
}
Se a la función, con lo que se obtiene la solución buscada (la altura de la torre de absorción):
abkx({x2, L1, x1, V1, y1, fkxky, fx, fy, S})
La función JavaScript equivalente a la función abkyi, es:
function abkyi({L1, x1, V1, y1, y2, fkpxkpy, fx, fy, S}={}) {
const B = L1*(1-x1);
const C = V1*(1-y1);
const D1 = B*x1/(1-x1)-C*y1/(1-y1);
const fkxi = y => {
const D3 = (C*y/(1-y)+D1)/B;
const x = D3/(1+D3);
const L = B/(1-x);
const V = C/(1-y);
const {kpx, kpy} = fkpxkpy({L, x, V, y, S});
const {yi, yim} = xiyi2({x, y, kpx, kpy, fx, fy});
return yim*V/(kpy*S*(1-y)*(y-yi));
};
return fkxi.simpson({a:y2, b:y1, n:10});
}
Para resolver, con esta función, el ejemplo 5.4.2.5, con los datos del ejemplo 5.4.2.1, se escribe la instrucción:
abkyi({L1, x1, V1, y1, y2, fkpxkpy, fx, fy, S})
La función JavaScript equivalente a la función abky, es:
function abky({L1, x1, V1, y1, y2, fkxky, fx, fy, S}={}) {
const B = L1*(1-x1);
const C = V1*(1-y1);
const D1 = B*x1/(1-x1)-C*y1/(1-y1);
const fkxi = y => {
const D3 = (C*y/(1-y)+D1)/B;
const x = D3/(1+D3);
const L = B/(1-x);
const V = C/(1-y);
const {kx, ky} = fkxky({L, x, V, y, S});
const {yi} = xiyi1({x, y, kpx:kx, kpy:ky, fx, fy});
return V/(ky*S*(1-y)*(y-yi));
};
return fkxi.simpson({a:y2, b:y1, n:10});
}
Para resolver, con esta función, el ejemplo 5.4.2.7, con los datos del ejemplo 5.4.2.1, se escribe la instrucción:
abky({L1, x1, V1, y1, y2, fkxky, fx, fy, S})
La función JavaScript equivalente a la función abKxi, es:
function abKxi({x2, L1, x1, V1, y1, fKpx, fy, S}={}) {
const B = L1*(1-x1);
const C = V1*(1-y1);
const D1 = B*x1/(1-x1)-C*y1/(1-y1);
const fKxi = x => {
const D2 = (B*x/(1-x)-D1)/C;
const y = D2/(1+D2);
const L = B/(1-x);
const V = C/(1-y);
const Kpx = fKpx();
const xa = fy(y);
const xam = ((1-x)-(1-xa))/Math.log((1-x)/(1-xa));
return xam*L/(Kpx*S*(1-x)*(xa-x));
};
const z = fKxi.simpson({a:x2, b:x1, n:10});
return z;
}
Para resolver con esta función el ejemplo 5.4.2.9, asumiendo que los datos del ejemplo 5.4.2.1 corresponden a un columna real, se procede de la siguiente forma.
Primero con los datos del ejemplo 5.4.2.1 y asumiendo que la altura calculada en ese ejemplo (1.57 m), es la altura real de un equipo de absorción, se calcula el coeficiente global ideal (Kpx), asumiendo valores del coeficiente hasta que la altura calculada (con abKxi) sea igual a la altura conocida (1.57 m). La función que devuelve 0, cuando se cumple que la altura calculada es igual a la conocida, es:
Esta función puede ser resuelta con uno de los métodos, para resolver ecuaciones algebraicas no lineales. Así, empleando el método de secante (como en el texto), se obtiene:
Kpx = fK.secante({xi:0.8, xf:0.81})
Por supuesto se podría emplear otro método, por ejemplo Regula-Falsi:
Kpx = fK.refa({xi:0.1, xf:0.9})
Ahora, con el coeficiente global ideal calculado (Kpx) y el porcentaje de absorción fijado (pa=98), se calculan los nuevos valores del flujo molar y fracción molar final del líquido (L1n, xin):
Entonces, para empleando el flujo y composición finales correspondientes al nuevo porcentaje de absorción requerido (L1n, x1n), se calcula la altura de la torre:
Entonces, con el nuevo flujo y composición inicial requeridos (L1n, x1n) y el coeficiente calculado (Kpy), se calcula la nueva altura de la torre de absorción:
Entonces, con el nuevo flujo y composición final requeridos (L1n, x1n) y el coeficiente calculado (Ky), se calcula la nueva altura de la torre de absorción:
La referencia detallada de las funciones presentadas en este y en los anteriores capítulos (incluido el código de los programas elaborados), está disponible en el siguiente enlace (donde se irán incorporando otras funciones a medida que se las presente y utilice):