import sympy as sp
from IPython.display import display, Markdown
# Define variables
= sp.symbols('t, u')
t, u= sp.symbols('tau', real=True, positive=True)
tau
= sp.sqrt(tau**2 - (t - tau)**2)
et # using u = t - tau integral becomes
# E(t) = int from -tau to tau ( sqrt (tau^2 - u^2))
= sp.integrate(sp.sqrt(tau**2 - u**2), (u, -tau, tau))
integral_eu
= sp.solve(integral_eu - 1, tau)
tau_est
# Evaluate the numeric value of tau_est
= tau_est[0].evalf() tau_numeric
Solutions to workshop 11: Distribution of residence time
Lecture notes for chemical reaction engineering
Try following problems from Fogler 5e (Fogler (2016)) P 16-3, P 16-6, P 16-11
We will go through some of these problems in the workshop.
P 16-3
Consider the E(t) curve below.
Mathematically this hemi circle is described by these equations:
For 2\tau >= t >= 0, then E(t) = \sqrt{\tau^2 - (t - \tau)^2} min–1 (hemi circle)
For t > 2\tau, then E(t) = 0
What is the mean residence time?
What is the variance?
Integral of E(t):
= sp.latex(integral_eu)
integral_latex f"$$E(t) = {integral_latex}$$")) display(Markdown(
E(t) = \frac{\pi \tau^{2}}{2}
Solution for \tau
= sp.latex(sp.simplify(tau_est[0]))
tau_latex f"$$\\tau = {tau_latex}$$")) display(Markdown(
\tau = \frac{\sqrt{2}}{\sqrt{\pi}}
\tau = 0.798 min.
We can also solve this problem numerically
import numpy as np
from scipy.integrate import quad
from scipy.optimize import fsolve
from IPython.display import display, Markdown
# Define E(t) function
def et(t, tau):
if 0 <= t <= 2 * tau:
return np.sqrt(tau**2 - (t - tau)**2)
else:
return 0
# Function to find tau such that the integral equals 1
def integral(tau):
= quad(et, 0, 2 * tau, args=(tau,))
res, _ return res - 1
# Initial guess for tau
= 1
tau_guess
# Solve for tau
= fsolve(integral, tau_guess)[0]
tau_est
# Define the variance function
def variance_func(t, tau):
return (t - tau)**2 * et(t, tau)
# Calculate the variance using numerical integration
= quad(variance_func, 0, 2 * tau_est, args=(tau_est,)) variance_value, _
Using numerical method:
\tau \approx 0.798 min.
\sigma^2 \approx 0.159 min2.
P 16-6
An RTD experiment was carried out in a nonideal reactor that gave the following results:
E(t) = 0 | for | t < 1 \, min |
E(t) = 1.0 \, min^{-1} | for | 1 <= t <= 2 \, min |
E(t) = 0 | for | t > 2 \, min |
What are the mean residence time, t_m, and variance \sigma^2?
What is the fraction of the fluid that spends a time 1.5 minutes or longer in the reactor?
What fraction of fluid spends 2 minutes or less in the reactor?
What fraction of fluid spends between 1.5 and 2 minutes in the reactor?
Hand written solution, (Accompanying excel file).
import numpy as np
from scipy.integrate import quad
from IPython.display import display, Markdown
# Define E(t) function
def et(t):
if t < 1:
return 0
elif 1 <= t <= 2:
return 1.0
else:
return 0
# Mean residence time function
def tau_func(t):
return t * et(t)
# Variance function
def variance_func(t, tm):
return (t - tm)**2 * et(t)
# Calculate mean residence time (t_m)
= quad(tau_func, 0, np.inf)
tau, _
# Calculate variance (sigma^2)
= quad(variance_func, 0, np.inf, args=(tau,))
variance, _
# Fraction of fluid that spends 1.5 minutes or longer
= quad(et, 1.5, np.inf)
f1_5_inf, _
# Fraction of fluid that spends 2 minutes or less
= quad(et, 0, 2)
f0_2, _
# Fraction of fluid that spends between 1.5 and 2 minutes
= quad(et, 1.5, 2) f1_5_2, _
Mean Residence Time \tau \approx 1.5000 min.
Variance \sigma^2 \approx 0.0833 min^2.
Fraction of fluid that spends 1.5 minutes or longer: 0.50
Fraction of fluid that spends 2 minutes or less: 1.00
Fraction of fluid that spends between 1.5 and 2 minutes: 0.50
P 16-11
The volumetric flow rate through a reactor is 10 dm3/min. A pulse test gave the following concentration measurements at the outlet:
t (min) | c \times 10^5 | t (min) | c \times 10^5 |
---|---|---|---|
0 | 0 | 15 | 238 |
0.4 | 329 | 20 | 136 |
1.0 | 622 | 25 | 77 |
2 | 812 | 30 | 44 |
3 | 831 | 35 | 25 |
4 | 785 | 40 | 14 |
5 | 720 | 45 | 8 |
6 | 650 | 50 | 5 |
8 | 523 | 60 | 1 |
10 | 418 |
Plot the external-age distribution E(t) as a function of time.
Plot the external-age cumulative distribution F(t) as a function of time.
What are the mean residence time t_m and the variance, \sigma^2 ?
What fraction of the material spends between 2 and 4 minutes in the reactor?
What fraction of the material spends longer than 6 minutes in the reactor?
What fraction of the material spends less than 3 minutes in the reactor?
Plot the normalized distributions E(\Phi) and F(\Phi) as a function of (\Phi).
What is the reactor volume?
Plot the internal-age distribution I(t) as a function of time.
What is the mean internal age \alpha_m ?
Hand written solution, (Accompanying excel file).
import numpy as np
from scipy.integrate import quad
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
from IPython.display import display, Markdown
# Given data
= np.array([0, 0.4, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0,
t 8.0, 10.0, 15, 20, 25, 30, 35, 40, 45, 50, 60])
= np.array([0, 329, 622, 812, 831, 785, 720, 650,
c 523, 418, 238, 136, 77, 44, 25, 14, 8, 5, 1]) * 1e-5
# Flow rate
= 10 # dm^3/min
Q
# Normalize concentration to calculate E(t)
= np.trapz(c, t)
integral_c = c / integral_c
et
# Interpolation functions
= interp1d(t, et, kind='cubic', fill_value="extrapolate")
et_interp
# f_interp = lambda t: np.array([quad(et_interp, 0, ti)[0] for ti in t])
# Define cumulative distribution F(t)
def f_interp(t):
return np.array([quad(et_interp, 0, ti, limit=1000)[0] for ti in np.atleast_1d(t)])
# Mean residence time function
= lambda t: t * et_interp(t)
tau_func
# Variance function
= lambda t, tm: (t - tm)**2 * et_interp(t)
variance_func
# Calculate mean residence time (t_m)
= quad(tau_func, 0, np.max(t))
tau, _
# Calculate variance (σ²)
= quad(variance_func, 0, np.max(t), args=(tau,)) variance, _
# Plot E(t) and F(t)
= np.linspace(0, 60, 500)
t_plot = et_interp(t_plot)
et_plot = f_interp(t_plot)
f_plot
='E(t) experimental')
plt.scatter(t, et, label='E(t) fitted')
plt.plot(t_plot, et_plot, label'Time (min)')
plt.xlabel('E(t)')
plt.ylabel(min(t_plot), np.max(t_plot))
plt.xlim(np.0,0.1)
plt.ylim(
plt.legend() plt.show()
='F(t)')
plt.plot(t_plot, f_plot, label'Time (min)')
plt.xlabel('F(t)')
plt.ylabel(min(t_plot), np.max(t_plot))
plt.xlim(np.0,1)
plt.ylim(
plt.legend() plt.show()
# Calculate specific time fractions
= quad(et_interp, 2, 4)
fraction_2_to_4, _ = quad(et_interp, 6, np.max(t))
fraction_above_6, _ = quad(et_interp, 0, 3)
fraction_below_3, _
# Reactor volume calculation
= Q * tau volume
Mean Residence Time tau: \approx 9.88 min.
Variance \sigma^2: \approx 75.69 min^2
Specific Time Fractions:
Fraction of material that spends between 2 and 4 minutes: \approx 0.163
Fraction of material that spends longer than 6 minutes: \approx 0.578
Fraction of material that spends less than 3 minutes: \approx 0.193
Reactor Volume: V = Q \cdot \tau: \approx 98.83 dm^3
Normalized distrubution:
To calculate normalized RTD, we convert t to \Theta as \Theta = t/\tau.
The dimensionless RTD function is calculated as E (\Theta) = \tau E(t).
Normalized cumulative RTD: F(\Theta) = \int_0^\Theta E(\Theta)d\Theta
= t/tau
theta = tau * et
e_theta = interp1d(theta, e_theta, kind='cubic', fill_value="extrapolate")
e_theta_interp
= np.linspace(0, theta[-1], 500)
theta_plot = e_theta_interp(theta_plot)
e_theta_plot
='$E(\\Theta)$ experimental')
plt.scatter(theta, e_theta, label='$E(\\Theta)$ fitted')
plt.plot(theta_plot, e_theta_plot, label'$\\Theta$')
plt.xlabel('$E(\\Theta)$')
plt.ylabel(min(theta_plot), np.max(theta_plot))
plt.xlim(np.0,1)
plt.ylim(
plt.legend() plt.show()
= lambda t: np.array([quad(e_theta_interp, 0, ti)[0] for ti in t])
f_theta_interp = f_theta_interp(theta_plot)
f_theta_plot
='$F(\\Theta)$')
plt.plot(theta_plot, f_theta_plot, label'$\\Theta$')
plt.xlabel('F(t)')
plt.ylabel(min(theta_plot), np.max(theta_plot))
plt.xlim(np.0,1)
plt.ylim(
plt.legend() plt.show()
Internal age distribution
I(t) = \frac{1}{\tau} \left[ 1 - F(t) \right]
Mean internal age
\alpha_m = \int_0^\infty I(t)dt
= lambda t, tm: (1/tm) * (1 - f_interp(t))
internal_age = quad(lambda t: internal_age(t, tau), 0, np.max(t))
mean_internal_age, _
= internal_age(t_plot, tau)
it_plot
='I(t)')
plt.plot(t_plot, it_plot, label'Time (min)')
plt.xlabel('I(t)')
plt.ylabel(min(t_plot), np.max(t_plot))
plt.xlim(np.0,0.1)
plt.ylim(
plt.legend() plt.show()
Mean Internal age \alpha_m: \approx 1.03 min.
References
Citation
@online{utikar2024,
author = {Utikar, Ranjeet},
title = {Solutions to Workshop 11: {Distribution} of Residence Time},
date = {2024-03-24},
url = {https://cre.smilelab.dev//content/workshops/10-distribution-of-residence-time/solutions.html},
langid = {en}
}