CADET Chemical reaction simulation

Hi Cadet community,
I’m trying to make a simulation for CSTR in a series. I make a Jupyter notebook for it.

It appears the simulation was successfully run. The diagram is like this

Inlet (pump) – tubing – CSTR 1 – tubing – CSTR 2 – tubing – Outlet (sink)

I have a few questions:

  1. For tubings, we could describe them as LUMPED_RATE_WITHOUT_PORES. Is that right? If so, we could put the total porosity = 1.
  2. I have played with some configurations like reaction rate constant (k), flow rate (Q_cstr), and volume of reactor (V_cstr). They all changed the concentration profiles, which makes sense. However, when I tried to play with length and cross-section area of tubings, they didn’t affect the concentration profile. So I tried to play with the col_dispersion, assuming the longer it gets, the more dispersion we get. However, it doesn’t matter how much I changed, no parameters (col_length, cross_section_area, col_dispersion) affect the outcome of the concentration profile. I know there is something wrong, but couldn’t figure it out where. Do you know why?

A few more things I’d like to ask is Chemical reaction notebook from Tutorial with respect to the simulation in tubular reactor.

  1. If it is the tubular reactor, can we just use the LUMPED_RATE_WITHOUT_PORES. Why we have to use LUMPED_RATE_WITH_PORES?
  2. I understand the col_porosity = 1. However, I don’t understand why par_porosity = 1, and par_radius = 1e-6. I know they are arbitrary, but is it that there are particles as catalysts in there?

I uploaded the Notebooks here.

Thank you all for your time.
01_reactions_demonstration_solution.ipynb (92.7 KB)
cstr-in-series.ipynb (22.8 KB)

Yes, however the interface is a little bit different.

What are you plotting?

You can use any of the models. You don’t “have to” use the LRMP.

Since col_porosity = 1, the values of the other parameters don’t really matter. They need to be specified however, since CADET checks if they exist in the config. At some point, we should add a dedicated unit for the tubular reactor. I’m happy to review a PR if you are up to a challenge.

Hi Jo, thanks for the answers.

I’m plotting the concentration of components from the outlet. Let me put down the code in here so you don’t have to open the Notebook.

%run ../utils.ipynb

# Auxiliary variables
t_cycle = 100

init_c = [1.0, 0.0]                                         # mol/m^3

kfwd = [0.01]                                               # m^3/(mol.s)
kbwd = [0.0]                                                # m^3/(mol.s)

stoich = [-1, 
           1]

n_comp = len(init_c)

# CSTR
V_cstr = 0.05                                               # m^3                                                    
Q_cstr = 0.001                                              # m^3/s                                                
tau_cstr = V_cstr/Q_cstr                                    # s
t_cycle = 1200                                              # s                                             


# PFR presenting tubings between CSTR
length = 0.025                                              # m
cross_section_area = 0.01                                   # m^2

model = get_cadet_template(n_units=7)

# Unit operations
model.root.input.model.unit_000.unit_type = 'INLET'
model.root.input.model.unit_000.ncomp = n_comp
model.root.input.model.unit_000.inlet_type = 'PIECEWISE_CUBIC_POLY'

# PFR (tubing from pump to CSTR 1)
model.root.input.model.unit_001.unit_type = 'LUMPED_RATE_MODEL_WITHOUT_PORES'
model.root.input.model.unit_001.ncomp = n_comp
model.root.input.model.unit_001.col_length = length
model.root.input.model.unit_001.cross_section_area = cross_section_area
model.root.input.model.unit_001.total_porosity = 1
model.root.input.model.unit_001.col_dispersion = 0
model.root.input.model.unit_001.init_c = init_c

# CSTR 1
model.root.input.model.unit_002.unit_type = 'CSTR'
model.root.input.model.unit_002.ncomp = n_comp
model.root.input.model.unit_002.init_volume = V_cstr
model.root.input.model.unit_002.init_c = init_c

# PFR (tubing between CSTR 1 and CSTR 2)
model.root.input.model.unit_003.unit_type = 'LUMPED_RATE_MODEL_WITHOUT_PORES'
model.root.input.model.unit_003.ncomp = n_comp
model.root.input.model.unit_003.col_length = length
model.root.input.model.unit_003.cross_section_area = cross_section_area
model.root.input.model.unit_003.total_porosity = 1
model.root.input.model.unit_003.col_dispersion = 0
model.root.input.model.unit_003.init_c = init_c

# CSTR 2
model.root.input.model.unit_004.unit_type = 'CSTR'
model.root.input.model.unit_004.ncomp = n_comp
model.root.input.model.unit_004.init_volume = V_cstr
model.root.input.model.unit_004.init_c = init_c

# PFR (tubing between CSTR 2 and sink aka outlet)
model.root.input.model.unit_005.unit_type = 'LUMPED_RATE_MODEL_WITHOUT_PORES'
model.root.input.model.unit_005.ncomp = n_comp
model.root.input.model.unit_005.col_length = length
model.root.input.model.unit_005.cross_section_area = cross_section_area
model.root.input.model.unit_005.total_porosity = 1
model.root.input.model.unit_005.col_dispersion = 0
model.root.input.model.unit_005.init_c = init_c

# Outlet
model.root.input.model.unit_006.unit_type = 'OUTLET'
model.root.input.model.unit_006.ncomp = n_comp

model.root.input.solver.sections.nsec = 1
model.root.input.solver.sections.section_times = [0.0, t_cycle]
model.root.input.solver.sections.section_continuity = []
model.root.input.solver.user_solution_times = np.linspace(0, t_cycle, 1001)

model.root.input.model.unit_000.sec_000.const_coeff = init_c

model.root.input.model.connections.nswitches = 1
model.root.input.model.connections.switch_000.section = 0
model.root.input.model.connections.switch_000.connections = [
    0, 1, -1, -1, Q_cstr,
    1, 2, -1, -1, Q_cstr,
    2, 3, -1, -1, Q_cstr,
    3, 4, -1, -1, Q_cstr,
    4, 5, -1, -1, Q_cstr,
    5, 6, -1, -1, Q_cstr,
]

# Reaction
# CSTR 1
model.root.input.model.unit_002.reaction_model = 'MASS_ACTION_LAW'
model.root.input.model.unit_002.reaction_bulk.mal_kfwd_bulk = kfwd
model.root.input.model.unit_002.reaction_bulk.mal_kbwd_bulk = kbwd
model.root.input.model.unit_002.reaction_bulk.mal_stoichiometry_bulk = stoich

# CSTR 2
model.root.input.model.unit_004.reaction_model = 'MASS_ACTION_LAW'
model.root.input.model.unit_004.reaction_bulk.mal_kfwd_bulk = kfwd
model.root.input.model.unit_004.reaction_bulk.mal_kbwd_bulk = kbwd
model.root.input.model.unit_004.reaction_bulk.mal_stoichiometry_bulk = stoich

# Preparing to run simulation
set_discretization(model)

# Running simulation
run_simulation(model)

time = model.root.output.solution.solution_times
solution_outlet = model.root.output.solution.unit_006.solution_outlet
plt.plot(time, solution_outlet)

Hi Hoang,

Your code looks correct - I did notice though that the volume of the CSTRs are much greater (200x) than the volumes of the tubings (with the current parameters). I imagine that changing the tubing size and dispersion don’t have much of an impact because the residence time of the fluid in the tubings is very small. I haven’t actually run your code though, so I could be mistaken.

2 Likes

Hi @alters. You are correct. After I reduced the ratio of volume of reactor and the tubings to 20-50-ish, the concentration profiles changed. I was just trying to get the code correct and forgot this part. Many thanks for spotting this :slight_smile:

3 Likes

No problem! Glad that worked.