Note
Go to the end to download the full example code.
Plug flow reactor modeled as a chain of well stirred reactors#
This example solves a plug flow reactor problem, where the chemistry is surface chemistry. The specific problem simulated is the partial oxidation of methane over a platinum catalyst in a packed bed reactor. To avoid needing to solve a DAE system, the PFR is approximated as a chain of successive WSRs. See surf_pfr.py for a more advanced implementation that solves the DAE system directly.
Requires: cantera >= 3.0
Input Parameters#
tc = 800.0 # Temperature in Celsius
length = 0.3 * cm # Catalyst bed length
area = 1.0 * cm**2 # Catalyst bed area
cat_area_per_vol = 1000.0 / cm # Catalyst particle surface area per unit volume
velocity = 40.0 * cm / minute # gas velocity
porosity = 0.3 # Catalyst bed porosity
# input file containing the surface reaction mechanism
yaml_file = 'methane_pox_on_pt.yaml'
output_filename = 'surf_pfr_output.csv'
# The PFR will be simulated by a chain of 'NReactors' stirred reactors.
NReactors = 201
dt = 1.0
t = tc + 273.15 # convert to Kelvin
# import the phase models and set the initial conditions
surf = ct.Interface(yaml_file, 'Pt_surf')
surf.TP = t, ct.one_atm
gas = surf.adjacent['gas']
gas.TPX = t, ct.one_atm, 'CH4:1, O2:1.5, AR:0.1'
rlen = length/(NReactors-1)
rvol = area * rlen * porosity
# catalyst area in one reactor
cat_area = cat_area_per_vol * rvol
mass_flow_rate = velocity * gas.density * area * porosity
# The plug flow reactor is represented by a linear chain of zero-dimensional
# reactors. The gas at the inlet to the first one has the specified inlet
# composition, and for all others the inlet composition is fixed at the
# composition of the reactor immediately upstream. Since in a PFR model there
# is no diffusion, the upstream reactors are not affected by any downstream
# reactors, and therefore the problem may be solved by simply marching from
# the first to last reactor, integrating each one to steady state.
TDY = gas.TDY
cov = surf.coverages
print(' distance X_CH4 X_H2 X_CO')
# create a new reactor
gas.TDY = TDY
r = ct.IdealGasReactor(gas, energy='off')
r.volume = rvol
# create a reservoir to represent the reactor immediately upstream. Note
# that the gas object is set already to the state of the upstream reactor
upstream = ct.Reservoir(gas, name='upstream')
# create a reservoir for the reactor to exhaust into. The composition of
# this reservoir is irrelevant.
downstream = ct.Reservoir(gas, name='downstream')
# Add the reacting surface to the reactor. The area is set to the desired
# catalyst area in the reactor.
rsurf = ct.ReactorSurface(surf, r, A=cat_area)
# The mass flow rate into the reactor will be fixed by using a
# MassFlowController object.
m = ct.MassFlowController(upstream, r, mdot=mass_flow_rate)
# We need an outlet to the downstream reservoir. This will determine the
# pressure in the reactor. The value of K will only affect the transient
# pressure difference.
v = ct.PressureController(r, downstream, primary=m, K=1e-5)
sim = ct.ReactorNet([r])
output_data = []
for n in range(NReactors):
# Set the state of the reservoir to match that of the previous reactor
gas.TDY = r.thermo.TDY
upstream.syncState()
sim.reinitialize()
sim.advance_to_steady_state()
dist = n * rlen * 1.0e3 # distance in mm
if n % 10 == 0:
print(' {0:10f} {1:10f} {2:10f} {3:10f}'.format(
dist, *r.thermo['CH4', 'H2', 'CO'].X))
# write the gas mole fractions and surface coverages vs. distance
output_data.append(
[dist, r.T - 273.15, r.thermo.P / ct.one_atm]
+ list(r.thermo.X) # use r.thermo.X not gas.X
+ list(rsurf.kinetics.coverages) # use rsurf.kinetics.coverages not surf.coverages
)
with open(output_filename, 'w', newline="") as outfile:
writer = csv.writer(outfile)
writer.writerow(['Distance (mm)', 'T (C)', 'P (atm)'] +
gas.species_names + surf.species_names)
writer.writerows(output_data)
print("Results saved to '{0}'".format(output_filename))
distance X_CH4 X_H2 X_CO
0.000000 0.093002 0.001365 0.010247
0.150000 0.043947 0.145965 0.029179
0.300000 0.033928 0.173629 0.035129
0.450000 0.028437 0.188531 0.038647
0.600000 0.024724 0.198522 0.041114
0.750000 0.021957 0.205922 0.042996
0.900000 0.019778 0.211726 0.044503
1.050000 0.017997 0.216453 0.045751
1.200000 0.016503 0.220406 0.046809
1.350000 0.015227 0.223777 0.047721
1.500000 0.014119 0.226696 0.048517
1.650000 0.013147 0.229253 0.049221
1.800000 0.012286 0.231516 0.049848
1.950000 0.011516 0.233534 0.050411
2.100000 0.010825 0.235347 0.050919
2.250000 0.010199 0.236984 0.051380
2.400000 0.009630 0.238471 0.051801
2.550000 0.009112 0.239826 0.052186
2.700000 0.008636 0.241066 0.052540
2.850000 0.008200 0.242206 0.052866
3.000000 0.007797 0.243255 0.053167
Results saved to 'surf_pfr_output.csv'
Total running time of the script: (0 minutes 0.335 seconds)