Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Pressure-Velocity Coupled 2D Fixed-Bed Reactor

Background

This notebook compares a one-dimensional constant-pressure reference model with a two-dimensional, wall-cooled packed-bed model for the gas-phase reaction

A→B+C.A \rightarrow B + C.

The chemistry and the feed follow the fixed-bed reactor exercise: pure A at 293 K with an interstitial velocity of 2 m/s at 1 bar. The 1D reference is solved at a constant 1 bar; the 2D model receives the same inlet molar flux and has its outlet at 1 bar, so its inlet pressure is part of the solution. The 1D reference shows the expected axial conversion, temperature rise and velocity increase when pressure is fixed and the reactor is adiabatic.

The 2D model keeps the same reaction and the same inlet molar flux, but resolves the tube radially, cools it through the wall and solves concentrations, temperature and pressure in one coupled steady residual. The gas flows through a packed bed, so the velocity follows from the local pressure gradient by Darcy’s law. The pressure is then a genuine two-dimensional field: it redistributes the flow radially when the gas near the axis is hotter and expands more than the gas near the wall.

The purpose of the notebook is to show how pressure-velocity coupling fits into the same finite-volume residual structure as species and heat balances, which row determines the pressure, and how to check that the result is right.

Governing Equations

The model is a steady, pseudo-homogeneous description of a packed tube of radius RR and length LL in cylindrical coordinates (z,r)(z, r). The unknown field on every cell is

x(z,r)=(cA,cB,cC,T,p)T,\mathbf{x}(z,r) = \left(c_A, c_B, c_C, T, p\right)^T,

with the concentrations cic_i in mol per m3^3 of gas. Fluxes are per m2^2 of bed cross-section (superficial) and rates per m3^3 of bed, which is why the porosity ε\varepsilon multiplies the rate.

Flow. The superficial velocity follows from Darcy’s law with the viscous (Blake-Kozeny) part of the Ergun equation,

u=−Kμ(T)∇p,K=ε3dp2150 (1−ε)2,μ(T)=μ0(TT0)0.7.\mathbf{u} = -\frac{K}{\mu(T)}\nabla p, \qquad K = \frac{\varepsilon^3 d_p^2}{150\,(1-\varepsilon)^2}, \qquad \mu(T) = \mu_0\left(\frac{T}{T_0}\right)^{0.7}.

The permeability is isotropic, so the same law gives the axial and the radial velocity. The interstitial velocity is u/ε\mathbf{u}/\varepsilon.

Species. With first-order Arrhenius kinetics,

∇⋅(u ci−Der∂ci∂rer)=νi ε rA,rA=k0exp⁡(−EaRT)cA,ν=(−1,1,1).\nabla\cdot\left(\mathbf{u}\,c_i - D_{er}\frac{\partial c_i}{\partial r}\mathbf{e}_r\right) = \nu_i\,\varepsilon\,r_A, \qquad r_A = k_0\exp\left(-\frac{E_a}{RT}\right)c_A, \qquad \nu = (-1, 1, 1).

Only radial dispersion is kept; axial dispersion is negligible at this bed length to particle size ratio. DerD_{er} is taken constant, a simplification: it is evaluated with a representative mean velocity instead of the local one.

Pressure row. No equation contains pp as its own unknown, so one balance must be chosen to determine it. Here it is total molar continuity written for the ideal-gas total concentration,

∇⋅(u ct−Der∂ct∂rer)=(∑iνi)ε rA,ct=pRT.\nabla\cdot\left(\mathbf{u}\,c_t - D_{er}\frac{\partial c_t}{\partial r}\mathbf{e}_r\right) = \left(\sum_i\nu_i\right)\varepsilon\,r_A, \qquad c_t = \frac{p}{RT}.

The sum of the three species rows is the same balance for s=∑icis = \sum_i c_i: the same discrete convection-dispersion operator with the same velocity field, the same source and the same total inlet flux. Subtracting the two, the difference s−cts - c_t satisfies a homogeneous convection-dispersion problem with zero inlet flux, whose only solution is zero. At convergence therefore

∑ici=pRT\sum_i c_i = \frac{p}{RT}

in every cell. The ideal gas law is a result of the model, not an imposed row. This only works if the pressure row uses exactly the same fluxes as the species rows, including the dispersive one; the Validation section shows what happens when it does not.

Energy. The energy balance is written in conservative enthalpy form, with the heat-capacity flux of the species fluxes Ni\mathbf{N}_i,

∇⋅(W (T−Tref)−λer∂T∂rer)=(−ΔHr) ε rA,W=∑iCp,iNi.\nabla\cdot\left(\mathbf{W}\,(T - T_\mathrm{ref}) - \lambda_{er}\frac{\partial T}{\partial r}\mathbf{e}_r\right) = (-\Delta H_r)\,\varepsilon\,r_A, \qquad \mathbf{W} = \sum_i C_{p,i}\mathbf{N}_i .

Because ∇⋅Ni=νiεrA\nabla\cdot\mathbf{N}_i = \nu_i\varepsilon r_A and ∑iνiCp,i=0\sum_i\nu_i C_{p,i} = 0 for the given heat capacities, ∇⋅W=0\nabla\cdot\mathbf{W} = 0, so this form equals W⋅∇T\mathbf{W}\cdot\nabla T without any artificial source from gas expansion. The face temperature is upwinded by the sign of W\mathbf{W}. The effective radial conductivity λer\lambda_{er} has a static and a dynamic (flow) contribution.

Boundary conditions. pymrm writes every boundary condition as

a∂ϕ∂n+b ϕ=d,a\frac{\partial \phi}{\partial n} + b\,\phi = d,

with nn the outward normal, so the sign of a gradient condition differs between the two ends of an axis.

  • Inlet, z=0z = 0: the molar fluxes Ni=yi,inNinN_i = y_{i,\mathrm{in}}N_\mathrm{in}, the enthalpy flux at TinT_\mathrm{in} and the total flux NinN_\mathrm{in} are given. The convective operator gets a zero face value there ({"a": 0, "b": 1, "d": 0}) and the given constant flux is added. Since the flux is given, the pressure has no Dirichlet value at the inlet: ∂p/∂n=0\partial p/\partial n = 0 ({"a": 1, "b": 0, "d": 0}), and the inlet pressure is part of the solution.

  • Outlet, z=Lz = L: p=poutp = p_\mathrm{out} ({"a": 0, "b": 1, "d": p_out}); all convected quantities leave with their cell value ({"outflow": True}). The pressure drop is an output of the model.

  • Axis, r=0r = 0: symmetry, ∂ϕ/∂n=0\partial\phi/\partial n = 0 for all fields.

  • Wall, r=Rr = R: impermeable, ∂p/∂n=0\partial p/\partial n = 0 gives ur=0u_r = 0, and no dispersive flux. Heat leaves as −λer ∂T/∂r=h (T−Tc)-\lambda_{er}\,\partial T/\partial r = h\,(T - T_c); with the outward normal +r+r this is λer ∂T/∂n+h T=h Tc\lambda_{er}\,\partial T/\partial n + h\,T = h\,T_c, the dictionary {"a": lam_er, "b": h, "d": h*T_c}.

Parameters and 1D Reference

The reference model uses molar flows per cross-sectional area, Fi=ciuF_i=c_i u, and temperature. At constant pressure,

ctot=PRT,ci=yictot.c_\mathrm{tot}=\frac{P}{RT}, \qquad c_i = y_i c_\mathrm{tot}.

This is the same variable-velocity constant-pressure formulation used in the fixed-bed exercise.

outlet conversion A 1.000000 outlet temperature [K] 443.000000 outlet velocity [m/s] 6.047782 dtype: float64

2D Model Settings

The 2D model uses the chemistry, the inlet state and the inlet molar flux of the reference calculation: the superficial molar flux Nin=ε vin pref/(RTin)N_\mathrm{in} = \varepsilon\, v_\mathrm{in}\, p_\mathrm{ref}/(R T_\mathrm{in}) carries the same moles per unit bed area as the 1D model with interstitial velocity vinv_\mathrm{in}. The bed and heat-transfer data are needed only for the 2D model. The table below is generated from the settings; its last column states the source of each value, and values marked “assumption” are not given by the exercise and were chosen to be representative for a small catalyst in a gas-cooled tube.

The radial dispersion coefficient uses the radial mass Peclet number of Fahien and Smith with the wall correction, as quoted by Froment and Bischoff,

Der=us dpPemr,Pemr=10[1+19.4(dpdt)2],D_{er} = \frac{u_s\, d_p}{\mathrm{Pe}_{mr}}, \qquad \mathrm{Pe}_{mr} = 10\left[1 + 19.4\left(\frac{d_p}{d_t}\right)^2\right],

and the effective radial conductivity is a static part plus a dynamic part with a heat Peclet number of 10,

λer=λer0+W dp10.\lambda_{er} = \lambda_{er}^0 + \frac{W\, d_p}{10}.
Loading...

PyMRM Implementation

The model follows the class-based pymrm pattern: build the grid and all constant operators once, evaluate the coupled physics in residual(...), return the residual together with its Jacobian, and let newton solve the steady problem.

  • Operators. Upwind interpolation matrices for both flow directions (construct_convflux_upwind with v=±1v = \pm 1), gradients with the boundary dictionaries above (construct_grad) and divergences in Cartesian zz and cylindrical rr (construct_div with nu=0 and nu=1). They do not depend on the state.

  • Fluxes. The face velocities come from the pressure gradient and the face temperature. Every convected quantity is upwinded by the sign of its own face velocity, so the discretisation stays well defined if the flow were to reverse during an iteration.

  • Exact Jacobian. A face flux is (velocity) times (upwinded face value), and the velocity is (mobility of TT) times (gradient of pp). The product rule applied to these constant matrices gives the exact Jacobian of all transport terms. Only the local reaction source, a 5×55\times 5 block per cell with the full Arrhenius temperature dependence, is differentiated numerically with NumJac.

  • Scaling. The state is scaled with the inlet concentration, the inlet temperature and a Darcy pressure scale around poutp_\mathrm{out}, and each row with its inlet flux per unit length. newton stops on an absolute step norm, so this scaling makes its tolerance meaningful for all five fields.

  • Initial guess. A 1D plug-flow solution with an overall wall coefficient, broadcast over the radius, with a Darcy pressure profile integrated back from the outlet. A step limiter caps the temperature change per iteration and keeps concentrations non-negative, for starts far from the solution.

The boundary dictionaries, written out as the equations they impose with describe_bc. Note the sign of the gradient term at the lower ends, where the outward normal points in the negative coordinate direction.

species, temperature (axial transport):
lower (z=0, outward normal -z): 0*dc_i/dz + 1*c_i = 0  [Dirichlet]
upper (z=0.5, outward normal +z): outflow, face value = adjacent cell value, zero diffusive flux
pressure (axial):
lower (z=0, outward normal -z): -1*dp/dz + 0*p = 0  [Neumann]
upper (z=0.5, outward normal +z): 0*dp/dz + 1*p = 101325  [Dirichlet]
species and pressure (radial), phi = c_i or p:
lower (r=0, outward normal -r): -1*dphi/dr + 0*phi = 0  [Neumann]
upper (r=0.006, outward normal +r): 1*dphi/dr + 0*phi = 0  [Neumann]
temperature (radial):
lower (r=0, outward normal -r): -1*dT/dr + 0*T = 0  [Neumann]
upper (r=0.006, outward normal +r): 0.54931*dT/dr + 40*T = 11720  [Robin]
success = True, Newton iterations = 6, CPU time 0.57 s
backward error = 1.2e-13 (ok = True)

Results

The table compares the 2D wall-cooled bed with the 1D adiabatic constant-pressure reference. The 2D outlet values are cup-mixing averages computed from the outlet face fluxes, the velocity is the area-averaged interstitial velocity at the outlet, and the pressure drop is the area-averaged inlet pressure minus poutp_\mathrm{out}.

Wall cooling removes a large part of the reaction heat: the outlet is much colder than in the adiabatic 1D model, and the conversion is slightly lower but still almost complete. The gas expands less because it is colder, so the outlet velocity is lower. The hot spot lies on the axis, where the heat has the longest path to the wall.

Loading...
<Figure size 1100x750 with 4 Axes>

The 2D fields show the radial structure that a 1D model cannot represent. The velocity panel shows the superficial axial velocity on the axial faces. It is almost uniform over the radius, as expected in a packed bed, but not exactly: where the axis is hotter the gas there is more viscous and expands more, and the pressure field redistributes the flow.

<Figure size 1200x720 with 8 Axes>
minimum axial velocity u_z = 0.743 m/s (no backflow), max |u_r| = 4.8e-03 m/s
largest radial pressure difference = 0.25 Pa (axial pressure drop 8346 Pa)
at the hot spot: u_z wall / u_z axis = 1.034
z = 0.0975 m: T axis 305.2 K, wall cell 303.2 K; c_A axis 35.89, wall cell 36.23 mol/m3
z = 0.3575 m: T axis 398.6 K, wall cell 379.7 K; c_A axis 0.74, wall cell 1.59 mol/m3
z = 0.4975 m: T axis 364.8 K, wall cell 352.2 K; c_A axis 0.05, wall cell 0.07 mol/m3
<Figure size 1100x400 with 2 Axes>

The radial profiles are taken in the cells nearest to zz = 0.1 m, at the hot spot and at the outlet. Near the inlet the reaction has hardly started and the profiles are nearly flat, within about 2 K. At the hot spot the axis is about 19 K hotter than the cell next to the wall, and cAc_A is lowest on the axis, where the reaction is fastest. At the outlet A is almost used up and the temperature relaxes towards the coolant.

Validation

A converged Newton iteration only proves that the discrete equations are satisfied. The checks below test that they are the right equations and that the grid resolves them: residual and Jacobian, conservation from the face fluxes, the ideal gas law as a consequence of the pressure row (with a break row that shows the check can fail), the adiabatic limit against the 1D reference, a second independent route to the pressure drop, and grid refinement.

Residual and Jacobian. residual_check evaluates the backward error of the converged state. check_jacobian compares the assembled Jacobian with central differences on a small grid, in a state perturbed away from the solution so that the radial velocity has both signs.

backward error 1.2e-13, max |g_hat| 5.1e-08, ok = True
Jacobian against central differences: max relative error 1.2e-06

Conservation. The total molar flow and the enthalpy are balanced with the face fluxes that the residual uses, not with interpolated fields: moles in plus moles produced must equal moles out, and the heat released by the reaction must leave either with the gas or through the wall.

molar flow:  in 3.763408e-03 + produced 3.748637e-03 = out 7.512045e-03 mol/s, relative error 1.7e-13
enthalpy:    released 56.23 W = out with the gas 24.47 W + to the wall 31.76 W, relative error 3.7e-14

Ideal gas law as a result. The pressure row makes ∑ici=p/(RT)\sum_i c_i = p/(RT) hold in every cell to round-off. The break row removes only the dispersive term −Der ∂ct/∂r-D_{er}\,\partial c_t/\partial r from the pressure row. The species rows still have it, the two operators now differ and the ideal gas law is violated by a few percent. A check that cannot fail proves nothing; this one fails when the pressure row is not the sum of the species rows.

model:     max |sum(c_i) R T / p - 1| = 6.7e-16
break row: max |sum(c_i) R T / p - 1| = 2.6e-02 (pressure row without -D_er dc_t/dr)

Adiabatic limit. With h=0h = 0 the solution must be radially uniform and must reproduce the 1D plug-flow reference: at full conversion the outlet temperature is fixed by the energy balance, and the outlet velocity by the ideal gas law at poutp_\mathrm{out}. The small velocity difference is a first-order discretisation error: the upwind face concentration at the outlet is the value in the last cell, where the pressure is higher than poutp_\mathrm{out} by half a cell of pressure drop, so the gas there is slightly denser and the outlet face velocity slightly lower. The cell below prints both relative differences.

h = 0: success = True, Newton iterations 7, radial T span 2.2e-12 K
outlet conversion  2D 1.000000   1D 1.000000
outlet T [K]       2D 443.00       1D 443.00
outlet v_int [m/s] 2D 6.0426       1D 6.0478
relative velocity difference -8.6e-04; last-cell pressure above p_out, relative 8.6e-04

Second route to the pressure drop. For h=0h = 0 the 2D model reduces to a 1D plug-flow model with Darcy flow, which can be integrated as an ODE for the molar flows, the temperature and the pressure. The inlet pressure is not known, so it is found by shooting until p(L)=poutp(L) = p_\mathrm{out}. This route shares no code with the finite-volume model. The gap between the two pressure drops is a discretisation error of the first-order upwind scheme, so it must shrink roughly by half each time the axial grid is refined.

1D Darcy ODE (shooting): pressure drop 11610 Pa
2D model, h = 0, n_r = 20:
  n_z =  50: pressure drop 11947 Pa, gap to the ODE 338 Pa
  n_z = 100: pressure drop 11775 Pa, gap to the ODE 165 Pa
  n_z = 200: pressure drop 11692 Pa, gap to the ODE 82 Pa

Grid refinement. Both directions are refined together by a factor 2. The first-order upwind scheme should give an observed order close to 1 for the outlet cup temperature; observed_orders also returns a Richardson estimate of the grid-converged value and of the error of the finest grid.

grids (n_z, n_r) = (50, 10), (100, 20), (200, 40)
outlet cup temperature [357.105 358.017 358.481] K
observed order 0.98, extrapolated 358.96 K (error estimate of the finest grid 0.48 K)

Modelling notes

Why Darcy flow, and why pressure is a 2D field. In an empty tube the laminar velocity profile is fixed by the wall and the axial pressure gradient; a model that prescribes a parabolic profile has no use for a radial pressure. In a packed bed the resistance comes from the particles, and the velocity follows the local pressure gradient in every direction. The pressure is then a genuine two-dimensional unknown: when the gas on the axis heats up and expands, its viscosity and volume flow rise, the pressure redistributes, and part of the flow moves towards the colder wall region. The streamtubes are not independent. The flow profile is almost flat, even near the wall, so there are no stagnant cells and no backflow; the minimum axial velocity and the radial pressure differences printed in the Results section confirm this.

Why a steady Newton solve with the exact Jacobian works. A model with a prescribed parabolic velocity profile leaves nearly stagnant cells at the wall, which typically forces pseudo-time stepping and a lagged Arrhenius factor. In the packed bed every cell is flushed, the transport operator is well conditioned, and the only strong nonlinearity is the Arrhenius term. With the exact Jacobian, including ∂rA/∂T\partial r_A/\partial T, Newton converges quadratically from the 1D cooled guess. The steady state is unique for these settings: starts from a cold, non-reacting guess and from the adiabatic guess reach the same solution.

start 'cold': success = True, Newton iterations 9, max |T - T_base| = 2.3e-12 K
start 'adiabatic': success = True, Newton iterations 10, max |T - T_base| = 2.2e-12 K

Effect of the wall coefficient. The overall coefficient hh is an assumption, so its effect should be known. A lower hh lets the bed run hotter: hh = 20 W m−2^{-2} K−1^{-1} gives full conversion, XX = 1.000, with a maximum temperature of 424.9 K. A higher hh removes the heat before the reaction ignites: hh = 100 W m−2^{-2} K−1^{-1} quenches the reaction to XX = 0.468. The response is smooth: there is no jump between ignited and extinguished states in this range, which is consistent with the unique steady state found above.

Loading...

Limits of Darcy flow. Darcy’s law keeps only the viscous term of the Ergun equation. Whether that is enough depends on the particle Reynolds number Rep=G dp/μ\mathrm{Re}_p = G\,d_p/\mu with the mass flux G=NinMG = N_\mathrm{in} M. The exercise does not give the molar mass, so the cell below evaluates the inlet Reynolds number for a light and a heavier gas, and the ratio of the full Ergun pressure gradient to the Darcy one,

(∂p/∂z)Ergun(∂p/∂z)Darcy=1+1.75150 Rep1−ε.\frac{\left(\partial p/\partial z\right)_\mathrm{Ergun}}{\left(\partial p/\partial z\right)_\mathrm{Darcy}} = 1 + \frac{1.75}{150}\,\frac{\mathrm{Re}_p}{1-\varepsilon}.

The mass flux is constant along the tube, so Rep\mathrm{Re}_p falls only through the viscosity as the gas heats up. At these Reynolds numbers Darcy under-predicts the pressure drop by a factor of about 2 to 3.4, depending on the molar mass and the position in the bed. The pressure drop, 8346 Pa, is about 8 % of the outlet pressure. It raises the gas density near the inlet and lowers the velocity there by a similar fraction. In the adiabatic bed this does not change the outlet state (conversion is complete and T=Tin+150T = T_\mathrm{in} + 150 K for any pressure), but in the cooled bed the changed residence time shifts the temperature profile by a few kelvin. A design calculation of the pressure drop itself needs the inertial term. The extension is to replace the Darcy velocity on each face by the solution of the quadratic Ergun law for the face pressure gradient Gp=∂p/∂nG_p = \partial p/\partial n,

u=−2 Gpa+a2+4 b ∣Gp∣,a=μK,b=1.75 (1−ε) ρε3dp,u = \frac{-2\,G_p}{a + \sqrt{a^2 + 4\,b\,\vert G_p\vert}}, \qquad a = \frac{\mu}{K}, \qquad b = \frac{1.75\,(1-\varepsilon)\,\rho}{\varepsilon^3 d_p},

which reduces to Darcy for b→0b \to 0, is smooth in GpG_p and still has an analytic derivative for the exact Jacobian. The density ρ=pM/(RT)\rho = pM/(RT) then also needs the molar masses.

M = 28 g/mol, inlet  (T = 293 K): Re_p =  60.4, Ergun / Darcy pressure gradient = 2.18
M = 28 g/mol, outlet (T = 358 K): Re_p =  52.5, Ergun / Darcy pressure gradient = 2.02
M = 58 g/mol, inlet  (T = 293 K): Re_p = 125.2, Ergun / Darcy pressure gradient = 3.43
M = 58 g/mol, outlet (T = 358 K): Re_p = 108.8, Ergun / Darcy pressure gradient = 3.12

Other simplifications. DerD_{er} is constant, evaluated with a representative velocity; a local Der=u dp/PemrD_{er} = u\,d_p/\mathrm{Pe}_{mr} would make it vary along the tube as the gas accelerates. The bed is pseudo-homogeneous: there are no particle-scale gradients, and the porosity is uniform, so the wall-channelling effect of the higher porosity near the wall is not represented.