Samir Hamdi

From Scholarpedia
Curator of ScholarpediaCurator Index: 0(Difference between revisions)
Jump to: navigation, search
m
Line 1: Line 1:
We now revisit the PDE problem of eqs. (1) to (4) to illustrate the details of
 
constructing a MOL code and to discuss the numerical and graphical output from
 
the code.
 
  
The specific initial condition of eq. (2) will be taken as:
 
 
:<math eq_2>
 
u(x,t=0) = sin(\pi x/2)
 
</math>
 
 
The analytical solution to eqs. (1) to (4) which we use to evaluate the numerical
 
MOL output is
 
 
:<math eq_2> 
 
u(x,t)=e^{-(\pi^{2}/4)t}sin(\pi x/2)
 
</math>
 
 
A main program in Matlab for the MOL solution of eqs. (1) to (4)
 
with the analytical solution, eq. (42), included for comparison with
 
the MOL solution, is listed below
 
 
<code><pre> 
 
 
%
 
% Clear previous files
 
  clear all
 
  clc
 
%
 
% Parameters shared with the ODE routine
 
  global ncall ndss
 
%
 
% Initial condition
 
  n=21;
 
  for i=1:n
 
    u0(i)=sin((pi/2.0)*(i-1)/(n-1));
 
  end
 
%
 
% Independent variable for ODE integration
 
  t0=0.0;
 
  tf=2.5;
 
  tout=linspace(t0,tf,n);
 
  nout=n;
 
  ncall=0;
 
%
 
% ODE integration
 
  mf=1;
 
  reltol=1.0e-04; abstol=1.0e-04;
 
  options=odeset('RelTol',reltol,'AbsTol',abstol);
 
  if(mf==1) % explicit FDs
 
    [t,u]=ode15s(@pde_1,tout,u0,options); end
 
  if(mf==2) ndss=4; % ndss = 2, 4, 6, 8 or 10 required
 
    [t,u]=ode15s(@pde_2,tout,u0,options); end
 
  if(mf==3) ndss=44; % ndss = 42, 44, 46, 48 or 50 required
 
    [t,u]=ode15s(@pde_3,tout,u0,options); end
 
%
 
% Store numerical and analytical solutions, errors at x = 1/2
 
  n2=(n-1)/2.0+1;
 
  sine=sin(pi/2.0*0.5);
 
  for i=1:nout
 
    u_plot(i)=u(i,n2);
 
    u_anal(i)=exp(-pi^2/4.0*t(i))*sine;
 
    err_plot(i)=u_plot(i)-u_anal(i);
 
  end
 
%
 
% Display selected output
 
  fprintf('\n mf = %2d  abstol = %8.1e  reltol = %8.1e\n',...
 
          mf,abstol,reltol);
 
  fprintf('\n    t      u(0.5,t)  u_anal(0.5,t)  err u(0.5,t)\n');
 
  for i=1:5:nout
 
    fprintf('%6.3f%15.6f%15.6f%15.7f\n',...
 
            t(i),u_plot(i),u_anal(i),err_plot(i));
 
  end
 
  fprintf('\n ncall = %4d\n',ncall);
 
%
 
% Plot numerical solution and errors at x = 1/2
 
  figure(1);
 
  subplot(1,2,1)
 
  plot(t,u_plot); axis tight
 
  title('u(0.5,t) vs t'); xlabel('t'); ylabel('u(0.5,t)')
 
  subplot(1,2,2)
 
  plot(t,err_plot); axis tight
 
  title('Err u(0.5,t) vs t'); xlabel('t'); ylabel('Err u(0.5,t)')
 
  print -deps pde.eps; print -dps pde.ps
 
%
 
% Plot numerical solution in 3D perspective
 
  figure(2);
 
  colormap('Gray');
 
  C=ones(n);
 
  g=linspace(0,1,n); % For distance x
 
  h1 = waterfall(t,g,u',C);
 
  axis('tight');
 
  grid off
 
  xlabel('t, time')
 
  ylabel('x, distance')
 
  zlabel('u(x,t)')
 
  s1 = sprintf('Diffusion Equation - MOL Solution');
 
  sTmp = sprintf('u(x,0) = sin(\\pi x/2 )');
 
  s2 = sprintf('Initial condition: %s', sTmp);
 
  title([{s1}, {s2}], 'fontsize', 12);
 
  v = [0.8616  -0.5076    0.0000  -0.1770
 
      0.3712    0.6301    0.6820  -0.8417
 
      0.3462    0.5876  -0.7313    8.5590
 
            0        0        0    1.0000];
 
  view(v);
 
  rotate3d on;
 
 
</pre></code>
 
 
We can note the following points about this main program:
 
 
* After declaring some parameters <tt> global </tt> so that they can be shared with other routines called via this main program, initial condition (2) is computed over a 21-point grid in <math> x </math>
 
 
<code><pre> 
 
% Clear previous files
 
  clear all
 
  clc
 
%
 
% Parameters shared with the ODE routine
 
  global ncall ndss
 
%
 
% Initial condition
 
  n=21;
 
  for i=1:n
 
    u0(i)=sin((pi/2.0)*(i-1)/(n-1));
 
  end
 
</pre></code>
 
 
* The independent variable <math> t </math> is defined over the interval <math> 0 \leq t\leq 2.5 </math> again, a 21-point grid is used.
 
<code><pre> 
 
%
 
% Independent variable for ODE integration
 
  t0=0.0;
 
  tf=2.5;
 
  tout=linspace(t0,tf,n);
 
  nout=n;
 
  ncall=0;
 
</pre></code>
 
 
* The 21 ODEs are then integrated by a call to the Matlab integrator <tt> ode15s </tt>
 
<code><pre>
 
  mf=1;
 
  reltol=1.0e-04; abstol=1.0e-04;
 
  options=odeset('RelTol',reltol,'AbsTol',abstol);
 
  if(mf==1) % explicit FDs
 
    [t,u]=ode15s(@pde_1,tout,u0,options); end
 
  if(mf==2) ndss=4; % ndss = 2, 4, 6, 8 or 10 required
 
    [t,u]=ode15s(@pde_2,tout,u0,options); end
 
  if(mf==3) ndss=44; % ndss = 42, 44, 46, 48 or 50 required
 
    [t,u]=ode15s(@pde_3,tout,u0,options); end
 
</pre></code>
 
Three cases are programmed corresponding to <tt> mf = 1, 2, 3 </tt> , for
 
which three different ODEs routines, <tt> pde_1 </tt>, <tt> pde_2 </tt>, and
 
<tt> pde_3 </tt> are called (these routines are discussed subsequently). The
 
variable <tt> ndss </tt> refers to a library of differentiation routines
 
for use in the MOL solution of PDEs; the use of <tt> ndss </tt> is illustrated
 
in the subsequent discussion. Note that a stiff integrator, <tt> ode15s </tt>,
 
was selected because the 21 ODEs are sufficiently stiff that a nonstiff
 
integrator results in a large number of calls to the ODE routine.
 
 
* Selected numerical results are stored for subsequent tabular and plotted output
 
<code><pre>
 
% Store numerical and analytical solutions, errors at x = 1/2
 
  n2=(n-1)/2.0+1;
 
  sine=sin(pi/2.0*0.5);
 
  for i=1:nout
 
    u_plot(i)=u(i,n2);
 
    u_anal(i)=exp(-pi^2/4.0*t(i))*sine;
 
    err_plot(i)=u_plot(i)-u_anal(i);
 
  end
 
</pre></code>
 
 
* Selected tabular numerical output is first displayed
 
<code><pre>
 
% Display selected output
 
  fprintf('\n mf = %2d  abstol = %8.1e  reltol = %8.1e\n',...
 
          mf,abstol,reltol);
 
  fprintf('\n    t      u(0.5,t)  u_anal(0.5,t)  err u(0.5,t)\n');
 
  for i=1:5:nout
 
    fprintf('%6.3f%15.6f%15.6f%15.7f\n',...
 
            t(i),u_plot(i),u_anal(i),err_plot(i));
 
  end
 
  fprintf('\n ncall = %4d\n',ncall);
 
</pre></code>
 
 
The output from this code is
 
 
<code><pre>
 
mf =  1  abstol = 1.0e-004  reltol = 1.0e-004
 
 
    t      u(0.5,t)  u_anal(0.5,t)  err u(0.5,t)
 
0.000      0.707107      0.707107      0.0000000
 
0.625      0.151387      0.151268      0.0001182
 
1.250      0.032370      0.032360      0.0000093
 
1.875      0.006894      0.006923    -0.0000283
 
2.500      0.001472      0.001481    -0.0000091
 
ncall =  85
 
 
</pre></code>
 
 
This output indicates that the MOL solution agrees with the analytical
 
solution to at least three significant figures. Also, <tt> ode15s </tt>
 
calls the derivative routine only 85 times (in contrast with the nonstiff
 
integrator <tt> ode45 </tt> that requires approximately 5000 - 10000 calls,
 
which clearly indicates the advantage of a stiff integrator for this
 
problem).
 
 
* The MOL solution and its error (computed from the analytical solution) are plotted
 
 
<code><pre>
 
% Plot numerical solution and errors at x = 1/2
 
  figure(1);
 
  subplot(1,2,1)
 
  plot(t,u_plot); axis tight
 
  title('u(0.5,t) vs t'); xlabel('t'); ylabel('u(0.5,t)')
 
  subplot(1,2,2)
 
  plot(t,err_plot); axis tight
 
  title('Err u(0.5,t) vs t'); xlabel('t'); ylabel('Err u(0.5,t)')
 
  print -deps pde.eps; print -dps pde.ps
 
</pre></code>
 
 
 
The plotted error output below indicates that the error in the MOL
 
solution varied between approximately <math> -3\times 10^{-5} </math> and
 
<math>16\times 10^{-5}</math> which is not quite within the error range specified in the
 
program
 
 
<code><pre>
 
 
    reltol=1.0e-04; abstol=1.0e-04;
 
 
</pre></code>
 
 
The fact that these error tolerances were not satisfied does not necessarily
 
mean that <tt> ode15s </tt> failed to adjust the integration interval to meet
 
these error tolerances.  Rather, the error of approximately <math> 1.6 \times 10^{-4} </math>
 
is due to the limited accuracy of the second order FD approximation of <math> \frac{\partial ^2 u}
 
{\partial x^2} </math> programmed in  <tt> pde_1 </tt>.  This conclusion is confirmed when
 
the main program calls <tt> pde_2 </tt> (for <tt> mf = 2 </tt> ) or <tt> pde_3 </tt>
 
(for <tt> mf = 3 </tt>) as discussed subsequently; these two routines have FD approximations that are more
 
accurate than in <tt> pde_1 </tt> so the errors fall below the specified tolerances.
 
 
 
This analysis indicates that two sources of errors result from the MOL solution
 
of PDEs such as eq. (1): (a) errors due to the integration in <math> t </math>
 
(by <tt> ode15s </tt>) and (b)
 
errors due to the approximation of the spatial derivatives such as
 
<math> \frac{\partial ^2 u}{\partial x^2} </math> programmed in the derivative routine such
 
as <tt> pde_1 </tt>.  In other words, we have to be attentive to integration
 
errors in the ''initial and boundary value independent variables''.
 
 
 
In summary, a comparison of the numerical and analytical solutions indicates that 21
 
grid points in <math> x </math> were not sufficient when using the second order FDs
 
in <tt> pde_1 </tt>.
 
 
However, in general, we will not have an analytical solution such
 
as eq. (42) to determine if the number of spatial grid points is adequate.
 
In this case, some experimentation with the number of grid points,
 
and the observation of the resulting solutions to infer the degree
 
of accuracy or ''spatial convergence,'' may be required.
 
 
* A 3D plot is also produced
 
 
<code><pre>
 
% Plot numerical solution in 3D perspective
 
  figure(2);
 
  colormap('Gray');
 
  C=ones(n);
 
  g=linspace(0,1,n); % For distance x
 
  h1 = waterfall(t,g,u',C);
 
  axis('tight');
 
  grid off
 
  xlabel('t, time')
 
  ylabel('x, distance')
 
  zlabel('u(x,t)')
 
  s1 = sprintf('Diffusion Equation - MOL Solution');
 
  sTmp = sprintf('u(x,0) = sin(\\pi x/2 )');
 
  s2 = sprintf('Initial condition: %s', sTmp);
 
  title([{s1}, {s2}], 'fontsize', 12);
 
  v = [0.8616  -0.5076    0.0000  -0.1770
 
      0.3712    0.6301    0.6820  -0.8417
 
      0.3462    0.5876  -0.7313    8.5590
 
            0        0        0    1.0000];
 
  view(v);
 
  rotate3d on;
 
</pre></code>
 
 
The plotted output below clearly indicates the origin of the ''lines'' in the ''method of lines''
 
 
The programming of the approximating MOL/ODEs is in one of the three
 
routines called by <tt> ode15s </tt>.  We now consider each of these routines.
 
For <tt> mf = 1, pde_1 </tt> calls function <tt> ut=pde_1(t,u) </tt>
 
 
<code><pre>
 
 
function ut=pde_1(t,u)
 
%
 
% Problem parameters
 
  global ncall
 
  xl=0.0;
 
  xu=1.0;
 
%
 
% PDE
 
  n=length(u);
 
  dx2=((xu-xl)/(n-1))^2;
 
  for i=1:n
 
    if(i==1)    ut(i)=0.0;
 
    elseif(i==n) ut(i)=2.0*(u(i-1)-u(i))/dx2;
 
    else        ut(i)=(u(i+1)-2.0*u(i)+u(i-1))/dx2;
 
    end
 
  end
 
  ut=ut';
 
%
 
% Increment calls to pde_1
 
  ncall=ncall+1;
 
</pre></code>
 
 
We can note the following points about <tt> tt pde_1 </tt>:
 
 
* Some problem parameters are first defined
 
 
<code><pre>
 
 
function ut=pde_1(t,u)
 
%
 
% Problem parameters
 
  global ncall
 
  xl=0.0;
 
  xu=1.0;
 
 
</pre></code>
 
 
<tt> xl </tt> and <tt> xu </tt> could have also been set in the main program and passed
 
to <tt> pde_1 </tt> as global variables. The defining statement at the beginning
 
of <tt> pde_1 </tt> indicates that the independent variable <tt> t </tt> and dependent
 
variable vector <tt> u </tt> are inputs to <tt> pde_1 </tt>, while the output is the vector
 
of <tt> tt t </tt> dervatives, <tt> ut </tt>; in other words, all of the <tt> n </tt> ODE derivatives
 
in <tt> t </tt> must be defined in <tt> pde_1 </tt>.
 
 
* The finite difference approximation of eq. (1) is then programmed
 
 
<code><pre>
 
% PDE
 
  n=length(u);
 
  dx2=((xu-xl)/(n-1))^2;
 
  for i=1:n
 
    if(i==1)    ut(i)=0.0;
 
    elseif(i==n) ut(i)=2.0*(u(i-1)-u(i))/dx2;
 
    else        ut(i)=(u(i+1)-2.0*u(i)+u(i-1))/dx2;
 
  end
 
  end
 
  ut=ut';
 
</pre></code>
 
 
The number of ODEs (21) is determined by the length command <tt> n=length(u); </tt>
 
so that the programming is general (the number of ODEs can easily be
 
changed in the main program). The square of the FD interval, <tt> dx2 </tt>,
 
is then computed.
 
 
* The MOL programming of the 21 ODEs is done in the <tt> for </tt> loop. For BC
 
(3), the coding is
 
 
<code><pre>
 
 
    if(i==1) ut(i)=0.0;
 
</pre></code>
 
 
since the value of <math> u(x=0,t) = 0 </math> does not change after being set as
 
an initial condition in the main program (and therefore its time derivative
 
is zero).
 
 
* For BC (4), the coding is
 
 
<code><pre>
 
 
    elseif(i==n) ut(i)=2.0*(u(i-1)-u(i))/dx2;
 
 
</pre></code>
 
 
which follows directly from the FD approximation of BC (4) (eq. (37))
 
 
:<math>
 
u_x \approx \frac{u(i+1) - u(i-1)}{\Delta x} = 0
 
</math> 
 
 
or with  <math> i = n </math>
 
 
:<math>
 
u(n+1) = u(n-1)
 
</math>
 
 
Note that the ''fictitious value''  <math> u(n+1) </math> can then be replaced in the ODE
 
at <math>i=n</math> by <math>u(n-1) </math>.
 
 
* For the remaining interior points, the programming is
 
 
<code><pre>
 
    else ut(i)=(u(i+1)-2.0*u(i)+u(i-1))/dx2;
 
</pre></code>
 
 
 
 
which follows from the FD approximation of the second derivative (eq. (33))
 
 
 
:<math>
 
u_{xx} \approx \frac{(u(i+1) - 2u(i) + u(i-1))}{\Delta x^2}
 
</math>
 
 
 
* Since the Matlab ODE integrators require a column vector of derivatives, a final transpose of <tt> ut </tt> is required
 
 
<code><pre>
 
 
  ut=ut';
 
%
 
% Increment calls to pde_1
 
  ncall=ncall+1;
 
 
</pre></code>
 
 
 
Finally, the number of calls to <tt>  pde_1 </tt>  is incremented so that at the
 
end of the solution, the value of <tt>  ncall </tt>  displayed by the main program
 
gives an indication of the computational effort required to produce
 
the entire solution. The numerical and graphical output for this case
 
(<tt>mf=1</tt>) was discussed subsequently.
 
 
For <tt>mf=2</tt>, function <tt> pde_2 </tt> is called by <tt> ode15s </tt>
 
 
<code><pre>
 
 
function ut=pde_2(t,u)
 
%
 
% Problem parameters
 
  global ncall ndss
 
  xl=0.0;
 
  xu=1.0;
 
%
 
% BC at x = 0 (Dirichlet)
 
  u(1)=0.0;
 
%
 
% Calculate ux
 
  n=length(u);
 
  if    (ndss== 2) ux=dss002(xl,xu,n,u); % second order
 
  elseif(ndss== 4) ux=dss004(xl,xu,n,u); % fourth order
 
  elseif(ndss== 6) ux=dss006(xl,xu,n,u); % sixth order
 
  elseif(ndss== 8) ux=dss008(xl,xu,n,u); % eighth order
 
  elseif(ndss==10) ux=dss010(xl,xu,n,u); % tenth order
 
  end
 
%
 
% BC at x = 1 (Neumann)
 
  ux(n)=0.0;
 
%
 
% Calculate uxx
 
  if    (ndss== 2) uxx=dss002(xl,xu,n,ux); % second order
 
  elseif(ndss== 4) uxx=dss004(xl,xu,n,ux); % fourth order
 
  elseif(ndss== 6) uxx=dss006(xl,xu,n,ux); % sixth order
 
  elseif(ndss== 8) uxx=dss008(xl,xu,n,ux); % eighth order
 
  elseif(ndss==10) uxx=dss010(xl,xu,n,ux); % tenth order
 
  end
 
%
 
% PDE
 
  ut=uxx';
 
  ut(1)=0.0;
 
%
 
% Increment calls to pde_2
 
  ncall=ncall+1;
 
 
</pre></code>
 
We can note the following points about <tt> pde_2</tt>:
 
 
* The initial statements are the same as in <tt> pde_1 </tt>. Then the Dirichlet
 
BC at <math> x = 0 </math> is programmed
 
 
<code><pre>
 
% BC at x = 0 (Dirichlet)
 
  u(1)=0.0;
 
</pre></code>
 
 
Acually, the statement <tt> u(1)=0.0;</tt> has no effect since the dependent
 
variables can only be changed through their derivatives, i.e., <tt> ut(1) </tt>,
 
in the ODE derivative routine. This code was included just to serve
 
as a reminder of the BC at <math>x = 0<math>, which is programmed subsequently
 
 
* The first order spatial derivative <math> \frac{\partial u}{\partial x}=u_{x} </math>
 
is then computed
 
 
<code><pre>
 
% Calculate ux
 
  n=length(u);
 
  if (ndss==2)    ux=dss002(xl,xu,n,u); % second order
 
  elseif(ndss== 4) ux=dss004(xl,xu,n,u); % fourth order
 
  elseif(ndss== 6) ux=dss006(xl,xu,n,u); % sixth order
 
  elseif(ndss== 8) ux=dss008(xl,xu,n,u); % eighth order
 
  elseif(ndss==10) ux=dss010(xl,xu,n,u); % tenth order
 
  end
 
</pre></code>
 
 
 
Five library routines, <tt>  dss002</tt>  to <tt> dss010</tt>, are programmed that use second
 
order to tenth order FD approximations, respectively. Since <tt> ndss=4</tt>
 
is specified in the main program, <tt> dss004</tt> is used in the calculation
 
of <tt> ux</tt>.
 
 
* BC (4) is then applied followed by the calculation of the second
 
order spatial derivative from the first order spatial derivative
 
 
<code><pre>
 
% BC at x = 1 (Neumann)
 
  ux(n)=0.0;
 
%
 
% Calculate uxx
 
  if    (ndss== 2) uxx=dss002(xl,xu,n,ux); % second order
 
  elseif(ndss== 4) uxx=dss004(xl,xu,n,ux); % fourth order
 
  elseif(ndss== 6) uxx=dss006(xl,xu,n,ux); % sixth order
 
  elseif(ndss== 8) uxx=dss008(xl,xu,n,ux); % eighth order
 
  elseif(ndss==10) uxx=dss010(xl,xu,n,ux); % tenth order
 
  end
 
</pre></code>
 
 
Again, <tt> dss004</tt> is called which is the usual procedure (the order of
 
the FD approximation generally is not changed in computing higher
 
order derivatives from lower order derivative, a process termed ''stagewise
 
differentiation'').
 
 
* Finally, eq. (1) is programmed and the Dirichlet BC at <math> x = 0 </math>
 
(eq.(3)) is applied
 
 
<code><pre>
 
% PDE
 
  ut=uxx';
 
  ut(1)=0.0;
 
%
 
% Increment calls to pde_2
 
  ncall=ncall+1;
 
 
</pre></code>
 
 
Note the similarity of the code to the PDE (eq. (1)), and also the
 
transpose required by <tt> ode15s</tt>.
 
 
The numerical output for this case (<tt>mf=2</tt>) is
 
 
<code><pre>
 
mf =  2  abstol = 1.0e-004  reltol = 1.0e-004
 
 
    t      u(0.5,t)  u_anal(0.5,t)  err u(0.5,t)
 
0.000      0.707107      0.707107      0.0000000
 
0.625      0.151267      0.151268    -0.0000013
 
1.250      0.032318      0.032360    -0.0000418
 
1.875      0.006878      0.006923    -0.0000446
 
2.500      0.001467      0.001481    -0.0000138
 
 
ncall =  62
 
</pre></code>
 
 
 
The plotted error output below indicates that the error in the MOL
 
solution varied between approximately <math>-5\times 10^{-5}</math> and
 
<math>3.2\times 10^{-5}</math> which is within the error range specified in the
 
program
 
 
<code><pre>
 
 
    reltol=1.0e-04; abstol=1.0e-04;
 
 
</pre></code>
 
 
 
Thus, switching from the second order FDs in <tt>pde_1</tt> to fourth order
 
finite differences in <tt> pde_2</tt> reduced the ''spatial truncation error''
 
so that the MOL solution met the specified error tolerances.
 
 
For <tt> mf = 3</tt>, function <tt> pde_3</tt> is called by <tt> ode15s </tt>
 
 
<code><pre>
 
function ut=pde_3(t,u)
 
%
 
% Problem parameters
 
  global ncall ndss
 
  xl=0.0;
 
  xu=1.0;
 
%
 
% BC at x = 0
 
  u(1)=0.0;
 
%
 
% BC at x = 1
 
  n=length(u);
 
  ux(n)=0.0;
 
%
 
% Calculate uxx
 
  nl=1; % Dirichlet
 
  nu=2; % Neumann
 
  if    (ndss==42) uxx=dss042(xl,xu,n,u,ux,nl,nu); % second order
 
  elseif(ndss==44) uxx=dss044(xl,xu,n,u,ux,nl,nu); % fourth order
 
  elseif(ndss==46) uxx=dss046(xl,xu,n,u,ux,nl,nu); % sixth order
 
  elseif(ndss==48) uxx=dss048(xl,xu,n,u,ux,nl,nu); % eighth order
 
  elseif(ndss==50) uxx=dss050(xl,xu,n,u,ux,nl,nu); % tenth order
 
  end
 
%
 
% PDE
 
  ut=uxx';
 
  ut(1)=0.0;
 
%
 
% Increment calls to pde_3
 
  ncall=ncall+1;
 
 
</pre></code>
 
 
We can note the following points about <tt>pde_3</tt>:
 
 
* The initial statements are the same as in <tt> pde_1</tt>. Then the Dirichlet
 
BC at <math>x = 0</math> and the Neumann BC at <math>x = 1 </math> are programmed
 
 
<code><pre>
 
function ut=pde_3(t,u)
 
%
 
% Problem parameters
 
  global ncall ndss
 
  xl=0.0;
 
  xu=1.0;
 
%
 
% BC at x = 0
 
  u(1)=0.0;
 
%
 
% BC at x = 1
 
  n=length(u);
 
  ux(n)=0.0;
 
 
</pre></code>
 
 
Again, the statement <tt> u(1)=0.0 </tt>; has no effect (since the dependent
 
variables can only be changed through their derivatives, i.e., <tt> ut(1)</tt>,
 
in the ODE derivative routine). This code was included just to serve
 
as a reminder of the BC at <math> x = 0 </math>, which is programmed subsequently.
 
 
* The second order spatial derivative <math>\frac{\partial^{2}u}{\partial x^{2}}=u_{xx}</math>
 
is then computed
 
 
<code><pre>
 
% Calculate uxx
 
  nl=1; % Dirichlet
 
  nu=2; % Neumann
 
  if (ndss==42)    uxx=dss042(xl,xu,n,u,ux,nl,nu); % second order
 
  elseif(ndss==44) uxx=dss044(xl,xu,n,u,ux,nl,nu); % fourth order
 
  elseif(ndss==46) uxx=dss046(xl,xu,n,u,ux,nl,nu); % sixth order
 
  elseif(ndss==48) uxx=dss048(xl,xu,n,u,ux,nl,nu); % eighth order
 
  elseif(ndss==50) uxx=dss050(xl,xu,n,u,ux,nl,nu); % tenth order
 
  end
 
</pre></code>
 
 
Five library routines, <tt>dss042</tt> to <tt>dss050</tt>, are programmed that use second
 
order to tenth order FD approximations, respectively for a second
 
derivative. Since <tt> ndss=44</tt> is specified in the main program, <tt>dss0044</tt>
 
is used in the calculation of <tt> uxx</tt>. Also, these differentiation routines
 
have two parameters that specify the type of BCs: (a) <tt> nl = 1 </tt> or <tt> 2 </tt>
 
specify a Dirichlet or a Neumann BC, respectively, at the lower boundary
 
value of <math> x = xl (= 0)</math>; in this case, BC (3) is Dirichlet, so <tt> nl = 1</tt>
 
and (b) <tt> nu = 1</tt> or <tt> 2</tt> specify a Dirichlet or a Neumann BC, respectively,
 
at the upper boundary value of <math>x = xu (= 1)</math>; in this case, BC (4)
 
is Neumann, so <tt> nu = 2</tt>.
 
 
* Finally, eq. (1) is programmed and the Dirichlet BC at <math>x = 0</math> (eq. (3)) is applied
 
 
<code><pre>
 
%
 
% PDE
 
  ut=uxx';
 
  ut(1)=0.0;
 
%
 
% Increment calls to pde_3
 
  ncall=ncall+1;
 
 
</pre></code>
 
 
Again, the transpose is required by <tt> ode15s</tt>.
 
 
The numerical output for this case (<tt>mf=3</tt>) is
 
 
<code><pre>
 
 
mf =  3  abstol = 1.0e-004  reltol = 1.0e-004
 
 
    t      u(0.5,t)  u_anal(0.5,t)  err u(0.5,t)
 
0.000      0.707107      0.707107      0.0000000
 
0.625      0.151267      0.151268    -0.0000017
 
1.250      0.032318      0.032360    -0.0000420
 
1.875      0.006878      0.006923    -0.0000447
 
2.500      0.001467      0.001481    -0.0000138
 
 
ncall =  62
 
</pre></code>
 
 
The plotted error output below indicates that the error in the MOL
 
solution varied between approximately <math>-4.8\times 10^{-5}</math> and
 
<math>3.2\times 10^{-5}</math> which is within the error range specified in the
 
program
 
 
<code><pre>
 
    reltol=1.0e-04; abstol=1.0e-04;
 
</pre></code>
 
 
We conclude this example with the following observation:
 
As the solution approaches steady state, <math>t\rightarrow\infty</math>,<math>u_{t}\rightarrow 0</math> and
 
from eq. (1), <math>u_{xx}\rightarrow 0</math>. As the second derivative vanishes, the solution becomes
 
 
<code><pre>
 
u_{xx}=0
 
\end{equation*}
 
\begin{equation*}
 
u_{x}=c_{1}
 
\end{equation*}
 
\begin{equation*}
 
u=c_{1}x+c_{2}
 
</pre></code>
 
 
Thus, the steady state solution is linear in <math>x</math>, which can serve as
 
another check on the numerical solution (for BCs (3) and (4), <math>c_{1}=c_{2}=0</math>
 
and thus at steady state <math>u=0,</math> which also follows from the analytical
 
solution, eq. (42)). This type of special case analysis is often useful
 
in checking a numerical solution. In addition to mathematical conditions
 
such as the linear dependency on <math>x</math>, physical conditions can frequently
 
also be used to check solutions, e.g., conservation of mass, momentum
 
and energy.
 
 
Through this example application we have attempted to illustrate
 
the basic steps of MOL/PDE analysis to arrive at a numerical solution
 
of acceptable accuracy. We have also presented some basic ideas for
 
assessing accuracy with respect to time and space (e.g., <math>t</math> and <math>x</math>).
 
More advanced applications (e.g., problems expressed as systems of
 
nonlinear PDEs) can be analyzed using the same ideas discussed in this
 
example.  The authors will be glad to assist by providing codes for
 
other 1D, 2D and 3D PDE problems.
 

Revision as of 15:49, 29 November 2007

Personal tools
Namespaces

Variants
Actions
Navigation
Focal areas
Activity
Tools