Balance Equations

In engineering, there are 4 common balance equations from conservation principles including mass, momentum, energy, and species. General forms of each equation are shown below with the accumulation term on the left and inlet (in), outlet (out), generation (gen), and consumption (cons) terms on the right side of the equation.

$$ \mathrm{Accumulation = In - Out + Generation - Consumption} $$

Mass Balance

$$\frac{dm}{dt} = \frac{d(\rho\,V)}{dt} = \sum \dot m_{in} - \sum \dot m_{out}$$

Species Balance

A species balance tracks the number of moles n of species A in a control volume. The accumulation of A, d(nA)/dt, in a control volume is calculated by inlet, outlet, reaction generation, and reaction consumption rates.

$$\frac{dn_A}{dt} = \sum \dot n_{A_{in}} - \sum \dot n_{A_{out}} + \sum \dot n_{A_{gen}} - \sum \dot n_{A_{cons}}$$

The molar amount, nA is often measured as a concentration, cA and reaction rates are often expressed in terms of a specific reaction rate, rA, as a molar rate of generation per volume.

$$\frac{dc_A V}{dt} = \sum c_{A_{in}} \dot V_{in} - \sum c_{A_{out}} \dot V_{out} + r_A V$$

Momentum Balance

A momentum balance is the accumulation of momentum for a control volume equal to the sum of forces F acting on that control volume.

$$\frac{d(m\,v)}{dt} = \sum F$$

with m as the mass in the control volume and v as the velocity of the control volume.

Energy Balance

$$\frac{dE}{dt} = \frac{d(U+K+P)}{dt} = \sum \dot m_{in} \left( \hat h_{in} + \frac{v_{in}^2}{2g_c} + \frac{z_{in} g_{in}}{g_c} \right) \\ - \sum \dot m_{out} \left( \hat h_{out} + \frac{v_{out}^2}{2g_c} + \frac{z_{out} g_{out}}{g_c} \right) + Q + W_s $$

Kinetic (K) and potential (P) energy terms are omitted because the internal energy (due to temperature) is typically a much larger contribution than any elevation (z) or velocity (v) changes of a fluid for most chemical processes.

$$\frac{dh}{dt} = \sum \dot m_{in} \hat h_{in} - \sum \dot m_{out} \hat h_{out} + Q + W_s$$

The enthalpy, h, is related to temperature as m cp (T-Tref) where cp is the heat capacity. With a constant reference temperature (Tref), this reduces to the following.

$$m\,c_p\frac{dT}{dt} = \sum \dot m_{in} c_p \left( T_{in} - T_{ref} \right) - \sum \dot m_{out} c_p \left( T_{out} - T_{ref} \right) + Q + W_s$$

Exercise

Use a mass, species, and energy balance to describe the dynamic response in volume, concentration, and temperature of a well-mixed vessel.

The inlet (qf) and outlet (q) volumetric flowrates, feed concentration (Caf), and inlet temperature (Tf) can be adjusted. Initial conditions for the vessel are V= 1.0 L, Ca = 0.0 mol/L, and T=350 K. There is no reaction and no significant heat added by the mixer. There is a cooling jacket that can be used to adjust the outlet temperature. Show step changes in the process inputs.

Solution

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# define mixing model
def vessel(x,t,q,qf,Caf,Tf):
    # Inputs (4):
    # qf  = Inlet Volumetric Flowrate (L/min)
    # q   = Outlet Volumetric Flowrate (L/min)
    # Caf = Feed Concentration (mol/L)
    # Tf  = Feed Temperature (K)

    # States (3):
    # Volume (L)
    V = x[0]
    # Concentration of A (mol/L)
    Ca = x[1]
    # Temperature (K)
    T = x[2]

    # Parameters:
    # Reaction
    rA = 0.0

    # Mass balance: volume derivative
    dVdt = qf - q

    # Species balance: concentration derivative
    # Chain rule: d(V*Ca)/dt = Ca * dV/dt + V * dCa/dt
    dCadt = (qf*Caf - q*Ca)/V - rA - (Ca*dVdt/V)

    # Energy balance: temperature derivative
    # Chain rule: d(V*T)/dt = T * dV/dt + V * dT/dt
    dTdt = (qf*Tf - q*T)/V - (T*dVdt/V)

    # Return derivatives
    return [dVdt,dCadt,dTdt]

# Initial Conditions for the States
V0 = 1.0
Ca0 = 0.0
T0 = 350.0
y0 = [V0,Ca0,T0]

# Time Interval (min)
t = np.linspace(0,10,100)

# Inlet Volumetric Flowrate (L/min)
qf = np.ones(len(t))* 5.2
qf[50:] = 5.1

# Outlet Volumetric Flowrate (L/min)
q = np.ones(len(t))*5.0

# Feed Concentration (mol/L)
Caf = np.ones(len(t))*1.0
Caf[30:] = 0.5

# Feed Temperature (K)
Tf = np.ones(len(t))*300.0
Tf[70:] = 325.0

# Storage for results
V  = np.ones(len(t))*V0
Ca = np.ones(len(t))*Ca0
T  = np.ones(len(t))*T0

# Loop through each time step
for i in range(len(t)-1):
    # Simulate
    inputs = (q[i],qf[i],Caf[i],Tf[i])
    ts = [t[i],t[i+1]]
    y = odeint(vessel,y0,ts,args=inputs)
    # Store results
    V[i+1]  = y[-1][0]
    Ca[i+1] = y[-1][1]
    T[i+1]  = y[-1][2]
    # Adjust initial condition for next loop
    y0 = y[-1]

# Construct results and save data file
data = np.vstack((t,qf,q,Tf,Caf,V,Ca,T)) # vertical stack
data = data.T             # transpose data
np.savetxt('data.txt',data,delimiter=',')

# Plot the inputs and results
plt.figure()

plt.subplot(3,2,1)
plt.plot(t,qf,'b--',linewidth=3)
plt.plot(t,q,'b:',linewidth=3)
plt.ylabel('Flow Rates (L/min)')
plt.legend(['Inlet','Outlet'],loc='best')

plt.subplot(3,2,3)
plt.plot(t,Caf,'r--',linewidth=3)
plt.ylabel('Caf (mol/L)')
plt.legend(['Feed Concentration'],loc='best')

plt.subplot(3,2,5)
plt.plot(t,Tf,'k--',linewidth=3)
plt.ylabel('Tf (K)')
plt.legend(['Feed Temperature'],loc='best')
plt.xlabel('Time (min)')

plt.subplot(3,2,2)
plt.plot(t,V,'b-',linewidth=3)
plt.ylabel('Volume (L)')
plt.legend(['Volume'],loc='best')

plt.subplot(3,2,4)
plt.plot(t,Ca,'r-',linewidth=3)
plt.ylabel('Ca (mol/L)')
plt.legend(['Concentration'],loc='best')

plt.subplot(3,2,6)
plt.plot(t,T,'k-',linewidth=3)
plt.ylabel('T (K)')
plt.legend(['Temperature'],loc='best')
plt.xlabel('Time (min)')

plt.show()