Closed Loop Recycling Process#
In closed-loop recycling (CLR), the stock mixture is pumped over the column several times until the desired purity is achieved. The general structure of a CLR is shown below.
To realize the recycling, the output_state
of the column needs to be modified, leading to the following event structure:
For this example, consider a two-component system with a Langmuir isotherm.
Component System#
from CADETProcess.processModel import ComponentSystem
component_system = ComponentSystem(['A', 'B'])
Binding Model#
from CADETProcess.processModel import Langmuir
binding_model = Langmuir(component_system, name='langmuir')
binding_model.adsorption_rate = [0.04, 0.05]
binding_model.desorption_rate = [1, 1]
binding_model.capacity = [100, 100]
Unit Operations#
from CADETProcess.processModel import (
Inlet, Cstr, LumpedRateModelWithoutPores, Outlet
)
feed = Inlet(component_system, name='feed')
feed.c = [10, 10]
eluent = Inlet(component_system, name='eluent')
eluent.c = [0, 0]
pump = Cstr(component_system, name='pump')
pump.V = 1e-9
column = LumpedRateModelWithoutPores(component_system, name='column')
column.binding_model = binding_model
column.length = 0.6
column.diameter = 0.024
column.axial_dispersion = 4.7e-7
column.total_porosity = 0.7
outlet = Outlet(component_system, name='outlet')
Flow Sheet#
from CADETProcess.processModel import FlowSheet
flow_sheet = FlowSheet(component_system)
flow_sheet.add_unit(feed, feed_inlet=True)
flow_sheet.add_unit(eluent, eluent_inlet=True)
flow_sheet.add_unit(pump)
flow_sheet.add_unit(column)
flow_sheet.add_unit(outlet, product_outlet=True)
flow_sheet.add_connection(feed, column)
flow_sheet.add_connection(eluent, column)
flow_sheet.add_connection(column, outlet)
flow_sheet.add_connection(column, pump)
flow_sheet.add_connection(pump, column)
Process#
from CADETProcess.processModel import Process
process = Process(flow_sheet, 'clr')
Create Events and Durations#
Q = 60/(60*1e6)
process.add_event('feed_on', 'flow_sheet.feed.flow_rate', Q)
process.add_event('feed_off', 'flow_sheet.feed.flow_rate', 0.0)
process.add_event('eluent_off', 'flow_sheet.eluent.flow_rate', 0.0)
process.add_event('eluent_on', 'flow_sheet.eluent.flow_rate', Q)
process.add_event('recycle_on_state', 'flow_sheet.output_states.column', {'pump': 1})
process.add_event('recycle_on_pump', 'flow_sheet.pump.flow_rate', Q)
process.add_event('recycle_off_state', 'flow_sheet.output_states.column', {'outlet': 1})
process.add_event('recycle_off_pump', 'flow_sheet.pump.flow_rate', 0)
Event(name=recycle_off_pump, parameter_path=flow_sheet.pump.flow_rate, state=0, time=0.0, indices=[(slice(None, None, None),)])
Event dependencies#
To reduce the number of event times that need to be specified, event dependencies are specified which enforce that always either feed or eluent are being pumped through the column.
process.add_event_dependency('eluent_off', ['feed_on'])
process.add_event_dependency('recycle_on_state', ['feed_off'])
process.add_event_dependency('recycle_on_pump', ['feed_off'])
process.add_event_dependency('recycle_off_pump', ['recycle_off_state'])
process.add_event_dependency('eluent_on', ['recycle_off_state'])
Event Times#
Now, the cycle time is set to \(10~min\) and the feed_duration
to \(1~min\).
process.cycle_time = 2000
process.feed_off.time = 40
process.recycle_off_state.time = 1280
Simulate Process#
Here, the first plot shows the concentration profile at the column outlet. It is important to note that since part of this profile is recycled, the concentration profile at the system outlet must be considered (second plot) to evaluate the process performance.
if __name__ == '__main__':
from CADETProcess.simulator import Cadet
process_simulator = Cadet()
simulation_results = process_simulator.simulate(process)
simulation_results.solution.column.outlet.plot()
simulation_results.solution.outlet.inlet.plot()
Optimize Fractionation Times#
if __name__ == '__main__':
from CADETProcess.fractionation import FractionationOptimizer
fractionation_optimizer = FractionationOptimizer()
fractionator = fractionation_optimizer.optimize_fractionation(
simulation_results, purity_required=[0.95, 0.95]
)
print(fractionator.performance)
_ = fractionator.plot_fraction_signal()
Performance(mass=array([0.00038081, 0.00038351]), concentration=array([1.8019649 , 0.78253879]), purity=array([0.96352084, 0.95464984]), recovery=array([0.9520315 , 0.95877592]), productivity=array([0.00233828, 0.00235484]), eluent_consumption=array([0.52890639, 0.53265329]) mass_balance_difference=array([-5.53106626e-09, -7.14111788e-08]))
Peak Shaving#
The disadvantage of the CLR process is an increased dispersion due to multiple passes through the pump and additional piping.
To improve the overall process performance, the CLR process is often combined with peak shaving. In this process, the initial and final regions of the chromatogram with sufficient purity are “shaved off” during each cycle. Peak shaving can reduce the number of recycling cycles required, since a decreasing amount of components must be pumped across the column.