24. Multistage mixer-settlers#

Liquid-liquid extraction takes advantage of chemical interactions within a mixture to selectively recover (or remove) a solute using a solvent. In the context of fermentation product recovery, oleochemicals can be recovered using a hydrophobic solvent. Another classic example is biodiesel “washing”, where water is used to recover glycerol and unreacted alcohols from crude biodiesel. After extraction, the solvent (typically a more volatile component with a low heat of vaporization) is generally distilled and recycled.

The recovery and concentration of the solute (in the solvent) will depend on how much solvent is used. More solvent can lead to higher recoveries but at lower concentrations (which increases expenses associated to solvent recovery). Counter-current multistage liquid extraction (employing 2 or more stages) can increase the recovery and improve the attainable concentration of the product, but at the expence of higher capital costs. Therefore, we have a trade-off between the recovery efficiency and capital/operating expenses as a function of solvent usage and number of stages.

In this tutorial we will model the recovery of octanol (a medium-chain fatty alcohol) from a fementation broth using multistage mixer-settlers. We will also push and pull the model to quantify the trade-off between recovery and concentration as a function of design decisions.

Let’s start by simulating the multistage mixer-settler assuming 2 stages and an equal volume of solvent.

[1]:
import biosteam as bst
bst.nbtutorial()
bst.settings.set_thermo(['Water', 'Hexane', 'Hexanol'])
feed = bst.Stream(Water=96, Hexanol=4, units='m3/hr')
solvent = bst.Stream(Hexane=100, units='m3/hr')
mixer_settlers = bst.MultiStageMixerSettlers(
    ins=(feed, solvent),
    outs=('extract', 'raffinate'),
    N_stages=2,
    use_cache=True,
)
mixer_settlers.simulate()
mixer_settlers.show()
MultiStageMixerSettlers: M1
ins...
[0] feed
    phase: 'l', T: 298.15 K, P: 101325 Pa
    flow (kmol/hr): Water    5.31e+03
                    Hexanol  31.9
[1] solvent
    phase: 'l', T: 298.15 K, P: 101325 Pa
    flow (kmol/hr): Hexane  760
outs...
[0] extract
    phase: 'L', T: 298.15 K, P: 101325 Pa
    flow (kmol/hr): Water    11.3
                    Hexane   759
                    Hexanol  30.7
[1] raffinate
    phase: 'l', T: 298.15 K, P: 101325 Pa
    flow (kmol/hr): Water    5.3e+03
                    Hexane   0.806
                    Hexanol  1.22

The recovery is high (>99%) even at just 2 stages. This means it may be possible to reduce the solvent use substantially. Let’s have a look at the tradeoff in concentration as a function of solvent usage and number of stages.

[2]:
import numpy as np
import matplotlib.pyplot as plt

# Simulation function
def concentration_recovery_capital_cost(solvent_usage, N_stages):
    solvent.F_vol = feed.F_vol * solvent_usage
    mixer_settlers.N_stages = N_stages
    mixer_settlers.simulate()
    extract = mixer_settlers.extract
    recovery = 100 * extract.imol['Hexanol'] / feed.imol['Hexanol'] # %
    concentration = extract.imass['Hexanol'] / extract.F_vol # kg / m3
    capital_cost = mixer_settlers.installed_cost / 1e3
    return (recovery, concentration, capital_cost)

# Collect data
N_stages = [2, 5, 10]
solvent_usage = np.linspace(0.2, 1, 20) # Solvent to feed flow rate (by volume)
shape = (len(N_stages), len(solvent_usage))
recoveries = np.zeros(shape)
concentrations = np.zeros(shape)
capital_costs = np.zeros(shape)
for i, N in enumerate(N_stages):
    for j, s in enumerate(solvent_usage):
        recoveries[i, j], concentrations[i, j], capital_costs[i, j] = concentration_recovery_capital_cost(s, N)
[3]:
# Plot
bst.set_figure_size(aspect_ratio=1.1)
colors = [getattr(bst.colors, i).RGBn for i in ('blue', 'red', 'purple')]
fig, (ax_capex, ax_recovery, ax_concentration) = plt.subplots(3, 1)
for i, N in enumerate(N_stages):
    plt.sca(ax_capex)
    plt.plot(solvent_usage, capital_costs[i], color=colors[i], label=f'{N} stages')
    plt.sca(ax_recovery)
    plt.plot(solvent_usage, recoveries[i], color=colors[i], label=f'{N} stages')
    plt.sca(ax_concentration)
    plt.plot(solvent_usage, concentrations[i], color=colors[i], label=f'{N} stages')
xticks = [0.2, 0.4, 0.6, 0.8, 1]
bst.style_axis(ax_capex, yticks=[0, 200, 400, 600], xticks=xticks, xticklabels=False)
plt.sca(ax_capex)
plt.ylabel('Capital cost [10$^3 \cdot$USD]')

bst.style_axis(ax_recovery, yticks=[85, 90, 95, 100], xticks=xticks, xticklabels=False)
plt.sca(ax_recovery)
plt.ylabel('Recovery [%]')
plt.ylim([85, 100])
plt.legend()

bst.style_axis(ax_concentration, yticks=[20, 60, 100, 140], xticks=xticks)
plt.sca(ax_concentration)
plt.ylabel('Concentration [kg$\cdot$m$^3$]')
plt.xlabel('Solvent to feed ratio (by vol)')
plt.show()
../_images/tutorial_Mixer_settlers_4_0.png

Note how there is a trade-off between solute concentration in the extract and recovery as a function of solvent. Increasing the number of stages may improve the recovery, but can lead to greater capital costs.