Application Center - Maplesoft

App Preview:

Diffusion and reaction in a 1-D slab

You can switch back to the summary page by clicking here.

Learn about Maple
Download Application


 

Diffusion and Reaction in a One Dimensional Slab

> restart:

This example involves the concentration in plug flow reactor with axial dispersion. The governing ODE is

> ODE := diff(C[A](z),z,z)=k/D[A,B]*C[A](z): ODE;

[Maple Math]

where [Maple Math] is the diffusion coefficient and [Maple Math] is the concentration. The boundary conditions for this example are written in the following form.

> BC0 := C[A](0)=C[A,0]: BC0;

[Maple Math]

> BC1:= D(C[A])(L)=0: BC1;

[Maple Math]

Method 1

This problem has an analytical solution that is easily obtained with Maple. (It's easy with R4. If you are using R5 then you need to execute the follwoing read statement to load Joe Riel's patch to dsolve, which, otherwise, cannot handle indexed variables in this context!!)

> read `e:/maple/utils/dsolve.mtx`:

> dsolve({ODE, BC0,BC1},C[A](z));

[Maple Math]

We can express this in the more familir form involving hyperbolic functions as follows

> convert(%,trig);

[Maple Math]

Method 2

We shall also attempt a numerical solution. The problem is not straightforward because the ODE to be solved is second order and we will need an estimate of the first derivative in order to use the shooting method as described in the Polymath solution.

We define [Maple Math] as the first derivative term.

> ODE3:=diff(C[A](z),z)=y(z): ODE3;

[Maple Math]

The second derivative is obtained on differentiation.

> diff(ODE3,z);

[Maple Math]

Substitution of the original ODE gives the following expression for the ODE

> ODE4:=subs(ODE,%): ODE4;

[Maple Math]

The parameter values are specified

> Params :={D[A,B]=1.2e-9,k=1e-3};

[Maple Math]

and substituted into the set of differential equations.

> Deqns := subs(Params,{ODE3,ODE4});

[Maple Math]

The initial conditions are the known initial concentration and a guess for the unknown first derivative term.

> IC := {C[A](0)=0.2,y(0)=-130};

[Maple Math]

We combine the sets of ODEs and initial conditions.

> Alleqns := Deqns union IC;

[Maple Math]

dsolve is invoked to make a procedure for numerical computation of the result.

> g:=dsolve(Alleqns,{C[A](z),y(z)}, type=numeric, method=rkf45, output=procedurelist);

[Maple Math]

We compute the "solution" (subject to the guessed initial value of y) as follows

> g(1e-3);

[Maple Math]

where the value of 0.001 in the call to g is the final value of [Maple Math] .

We need to find an initial value of y that leads to [Maple Math] (more or less). We make a procedure to automate the preceding computations:

> f := proc(y0)
local IC, Deqns, Params, Alleqns,g, err;
Params :={D[A,B]=1.2e-9,k=1e-3, y[f,0]=0};
Deqns := {833333.3333*C[A](z) = diff(y(z),z), diff(C[A](z),z) = y(z)};
IC := {C[A](0)=0.2,y(0)=y0};
Alleqns := Deqns union IC;
g:=dsolve(Alleqns,{C[A](z),y(z)}, type=numeric, method=rkf45, output=procedurelist);
err := subs(Params,rhs(g(1e-3)[2]) - y[f,0]);
end:

and test it for some differing initial values

> f(-130);

[Maple Math]

> f(-140);

[Maple Math]

The different signs obtained above is an indication that there is a solution to this problem at a value of [Maple Math] somewhere between -130 and -140. In Maple Releave 4 we could ask fsolve to compute a numerical solution to this equation using the command shown below.

> # result:=fsolve('f'(y0),y0=-140..-130);

However, Release 5 is unable to solve this problem quite so easily, and we shall resort to using our own implementation of Newton's method. First we must rewrite the above proc so that it returns a list,

rather than a single number.

> f := proc(y0)
local IC, Deqns, Params, Alleqns,g, err;
Params :={D[A,B]=1.2e-9,k=1e-3, y[f,0]=0};
Deqns := {833333.3333*C[A](z) = diff(y(z),z), diff(C[A](z),z) = y(z)};
IC := {C[A](0)=0.2,y(0)=y0};
Alleqns := Deqns union IC;
g:=dsolve(Alleqns,{C[A](z),y(z)}, type=numeric, method=rkf45, output=procedurelist);
err := [subs(Params,rhs(g(1e-3)[2]) - y[f,0])];
end:

Now we can invoke Newton's method.

> read `e:/maple/numerics/nonlin/newton.mpl`:

> result:=Newton(f,y0=-135): result;

[Maple Math]

The value obtained above is the "correct" value of the first derivative at the origin. We need to compute all the other variables at the end using this value for the first derivative. To this end we repeat our initial computations, first remaking the initial condition.

> IC := {C[A](0)=0.2,y(0)=op(2,result)};

[Maple Math]

then reforming the full set of differential equations and initial conditions,

> Alleqns := Deqns union IC;

[Maple Math]

and asking dsolve to generate a procedure from which we may compute a numerical solution

> g:=dsolve(Alleqns,{C[A](z),y(z)}, type=numeric, method=rkf45, output=procedurelist);

[Maple Math]

Finally, we invoke the procedure to find the desired concentration.

> g(1e-3);

[Maple Math]

Method 3

Here, we are going to use a finite difference method of solving the ODE. Our first step is to stop using functional notation in the original equation

> ODE2:=subs(diff=Diff,C[A](z)=C[A],ODE): ODE2;

[Maple Math]

as well as in the boundary conditions

> BC0 := C[A](0)=C[A,0]: BC0;

[Maple Math]

> BC1:= Diff(C[A](L),z)=0: BC1;

[Maple Math]

The governing equation is assumed to hold for the concentration at certain selected points (nodes), here indicated by the index i.

> i:='i': ODE3:=subs(C[A]=C[A,i],ODE2): ODE3;

[Maple Math]

We set the number of nodes

> n:=11;

[Maple Math]

We use a central difference approximation to the second derivative in the above equation

> fddiff:=Diff(Diff(C[A,i],z),z) = (C[A,i+1]-2*C[A,i]+C[A,i-1])/h^2: fddiff;

[Maple Math]

We can now generate finite difference approximations for each interior node (the boundaries are dealt with separately below).

> for i from 2 to n-1 do
eqn[i] :=subs(fddiff,ODE3);
print(eqn[i]);
od:

[Maple Math]

[Maple Math]

[Maple Math]

[Maple Math]

[Maple Math]

[Maple Math]

[Maple Math]

[Maple Math]

[Maple Math]

The boundary condition at [Maple Math] is

> BC0a:=subs(C[A](0)=C[A,1],BC0): BC0a;

[Maple Math]

where [Maple Math] is the initial concentration. The derivative boundary condition at the other boundary must be replaced using a 2 term backward difference approximation

> fddiffb2:=Diff(C[A,i],z)=1/2*(3*C[A,i]-4*C[A,i-1]+C[A,i-2])/h: fddiffb2;

[Maple Math]

The second boundary condition now becomes

> BC1a:=subs(C[A](L)=C[A,i],fddiffb2,i=n,BC1): BC1a;

[Maple Math]

We place all the equations into a list.

> eqnlist :=[BC0a,seq(eqn[i],i=2..n-1),BC1a];

[Maple Math]
[Maple Math]
[Maple Math]

In order to obtain a numerical solution we must assign values to the diffusion coefficient, reaction rate coefficient and so on. The values used here are as follows.

> Params := {D[A,B]=1.2e-9,k=1e-3,h=1e-3/(n-1),C[A,0]=0.2};

[Maple Math]

The step size, [Maple Math] , is determined by the fact that the distance over which diffusion and reaction take place is just [Maple Math] m.

We substitute these variables into the finite difference equations.

> eqnlist2:=subs(Params,eqnlist);

[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]

The variables appearing in these equations are

> vars:=indets(eqnlist2,name);

[Maple Math]

and they number

> nops(vars);

[Maple Math]

The number of equations is

> nops(eqnlist2);

[Maple Math]

So there appear to be no further degrees of freedom. Before proceeding it might help to determine the structure of the equations. Here is a procedure for looking at the structure of equation sytems.

> Eqnanalysis := proc (Eqns::{set,list,vector},x::{set,list,vector})
local neqns, Imat, i, j;
# Determine number of equations
neqns := nops(Eqns);
# Now to construct the incidence matrix
Imat := linalg[matrix](neqns,neqns,0);
for i from 1 to neqns do
for j from 1 to neqns do
if has (Eqns[i], x[j]) then
Imat[i,j] := 1;
fi;
od;
od;
plots[sparsematrixplot](Imat);
end:

> Eqnanalysis(eqnlist2,[seq(C[A,i],i=1..n)]);

[Maple Plot]

Here we see that the system of equations has an almost tridiagonal form. We could, had we a mind to do so, take advantage of this structure in devising a suitable computational method for calculating the concentrations. In this case there is no need to do so since Maple can solve these equations directly.

> result:=solve({op(eqnlist2)},vars): result;

[Maple Math]
[Maple Math]

Maple can also solve the purely symbolic problem in which numerical values have not been given to the model parameters.

> solve({op(eqnlist)},vars);

[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]

We can check that this gives the same result as before on substituting the parameter values

> subs(Params,%);

[Maple Math]
[Maple Math]

As an alternative - not needed in this case but necessary in others - we could use Newton's method to solve the equations numerically.

> read `e:/maple/numerics/nonlin/newton.mpl`:

A list of initial guesses is created.

> Initial:=[seq(C[A,i]=0.2,i=1..n)];

[Maple Math]

We invoke Newton's method as follows:

> result:=Newton(eqnlist2,Initial,tolerance=1e-6,output={variables});

[Maple Math]

[Maple Math]
[Maple Math]

[Maple Math]
[Maple Math]

An advantage of this solution is that the concentrations at each node are listed in the original order.

The concentration profile can be plotted as shown in the next command.

> plot([seq([k,rhs(result[k])],k=1..n)],labels=['n','C']);

[Maple Plot]

Note the profile flattens out on the right hand side of the plot, as is to be expected from a boundary condition that forces to zero the concentration derivative.

Inspection of the iteration history shows that the solution was obtained in a single step (round off is responsible for the procedure taking the extra step). This means that the equations are linear (we could have deduced this fact if only we had bothered to look).

>