Cyclic Vacuum Swing Adsorption simulation

This example shows how to set up and run a cyclic vacuum swing adsorption simulation as described in Haghpanah et al. 2013

This simulation inolves injection of a two component flue gas (CO2 and N2) into a column of Zeolite 13X. The CO2 is preferentially adsorbed onto the zeolite. Pressure in the column is then reduced to enable desorption of CO2 for collection.

This is a four stage process comprising:

  • Pressurisation: Where the RHS of the column is closed and flue gas is injected from the LHS, at velocity $v_{feed}$, to bring the column pressure up to $P_H$ (Pressure High).
  • Adsorption: Where both ends of the column are open and flue gas is injected from the RHS at velocity $v_{feed}$. Pressure at the LHS is $P_H$.
  • Blowdown: Where the LHS of the column is closed and the column is evacuated at $P_I$ (Pressure Intermediate).
  • Evacuation: Where the RHS of the column is closed and the column is evacuated from the LHS at $P_L$ (Pressure Low).

Each stage is modelled using the same governing equations but with different boundary conditions. Adsorption onto Zeolite 13X is modelled with a dual-site Langmuir adsorption isotherm.

First we load the necessary modules

import Jutul: si_unit
import Mocca

We define parameters, and set up the system and domain as in the Simulate DCB example.

constants = Mocca.HaghpanahConstants{Float64}()
system = Mocca.TwoComponentAdsorptionSystem(constants);

Create the model

Now we can assemble the model which contains the domain and the system of equations.

ncells = 200
model = Mocca.setup_process_model(system; ncells = ncells);

Setup the initial state and parameters

Initial values for pressure and temperature of the system

bar = si_unit(:bar);
P_init = 1*bar;
T_init = 298.15;
Tw_init = constants.T_a;

To avoid numerical errors we set the initial CO2 concentration to be very small and not exactly zero

yCO2_2 = 1e-10
y_init = [yCO2_2, 1.0 - yCO2_2] # [CO2, N2]

state0 = Mocca.setup_process_state(model;
    Pressure = P_init,
    Temperature = T_init,
    WallTemperature = Tw_init,
    y = y_init
);

parameters = Mocca.setup_process_parameters(model);

Set up the stage timings and boundary conditions

Here we have 4 stages and we specify a duration in seconds that we will run each stage.

t_press = 15.0
t_ads = 15.0
t_blow = 30.0
t_evac= 40.0
stage_times = [t_press, t_ads, t_blow, t_evac];
stage_names = ["pressurisation", "adsorption", "blowdown", "evacuation"]
4-element Vector{String}:
 "pressurisation"
 "adsorption"
 "blowdown"
 "evacuation"

Set up cyclic boundary conditions and timesteps for the simulation We will run 3 cycles of the process for demonstration purposes, to reach steady state num_cycles should be increased.

sim_forces, timesteps = Mocca.setup_forces(model,stage_times,stage_names;
    num_cycles=3, max_dt = 1);

Simulate

Now we are ready to run the simulation

case = Mocca.MoccaCase(model, timesteps, sim_forces; state0 = state0, parameters = parameters)
states, timesteps_out = Mocca.simulate_process(case;
    output_substates = true,
    info_level = 0
);
Jutul: Simulating 5 minutes as 300 report steps
╭────────────────┬───────────┬───────────────┬───────────╮
│ Iteration type   Avg/step   Avg/ministep      Total │
│                 300 steps  304 ministeps   (wasted) │
├────────────────┼───────────┼───────────────┼───────────┤
│ Newton         │   2.64667 │       2.61184 │  794 (30) │
│ Linearization  │      3.66 │       3.61184 │ 1098 (32) │
│ Linear solver  │   2.64667 │       2.61184 │  794 (30) │
│ Precond apply  │       0.0 │           0.0 │     0 (0) │
╰────────────────┴───────────┴───────────────┴───────────╯
╭───────────────┬────────┬────────────┬────────╮
│ Timing type      Each    Relative   Total │
│                    ms  Percentage       s │
├───────────────┼────────┼────────────┼────────┤
│ Properties    │ 0.0551 │     2.05 % │ 0.0438 │
│ Equations     │ 0.5094 │    26.26 % │ 0.5593 │
│ Assembly      │ 0.0374 │     1.93 % │ 0.0410 │
│ Linear solve  │ 1.7123 │    63.82 % │ 1.3596 │
│ Linear setup  │ 0.0000 │     0.00 % │ 0.0000 │
│ Precond apply │ 0.0000 │     0.00 % │ 0.0000 │
│ Update        │ 0.0399 │     1.49 % │ 0.0317 │
│ Convergence   │ 0.0338 │     1.74 % │ 0.0371 │
│ Input/Output  │ 0.0288 │     0.41 % │ 0.0088 │
│ Other         │ 0.0617 │     2.30 % │ 0.0490 │
├───────────────┼────────┼────────────┼────────┤
│ Total         │ 2.6830 │   100.00 % │ 2.1303 │
╰───────────────┴────────┴────────────┴────────╯

Visualisation

We plot primary variables at the outlet through time

outlet_cell = ncells
f_outlet = Mocca.plot_cell(states, model, timesteps_out, outlet_cell)
Example block output

We also plot primary variables along the column at the end of the simulation

f_column = Mocca.plot_state(states[end], model)
Example block output

Example on GitHub

If you would like to run this example yourself, it can be downloaded from the Mocca.jl GitHub repository.


This page was generated using Literate.jl.