% test_integration.m

%

% This MATLAB program tests integration routines for the

% integral of exp(-x^2) over [0,1].

%

% K. Beers.

% MIT ChE. 8/7/2002

 

function iflag_main = test_integration();

 

iflag_main = 0;

 

% Set the limits of integration.

a = 0;

b = 1;

 

% Set a character string to define the function

% to be integrated.  We use .^ so that the function

% is overloaded - we can hand it multiple values of

% x at a time.

fun = 'exp(-x.^2)';

 

% We set the "true" value, known from the error function.

integral_true = sqrt(pi)/2*erf(1);

disp(['Integral (true value) = ', ...

        num2str(integral_true)]);

 

 

% trapz() ---------------------------------------------------------

% First, we demonstrate the use of the composite trapezoid rule.

 

% Make a vector of grid points at which to evaluate the function.

% In this example, we use evenly-spaced grid points; however, if

% you know that your function changes most rapidly in a particular

% region of the domain [a,b], you make the grid more fine in this

% region to provide higher accuracy with the same total number

% of grid points.

resolution = 10;  % number of grid points

x_val = linspace(a,b,resolution);  % x-values at grid points

% Compute the value of f from the function by making an inline function

F = inline(fun);  % we declare an inline function F

f_val = F(x_val);  % calculate values of f(x) at grid points

% We plot the function over [a,b].

figure;

plot(x_val,f_val);

xlabel('x');

ylabel('f(x)');

title(['f(x) = ', fun]);

% Then, we estimate the value of the integral using the

% composite trapezoid rule.  To increase the accuracy of

% the estimate, we increase the resolution.

integral_trap = trapz(x_val,f_val);

disp(['Integral (composite trapezoid) = ', ...

        num2str(integral_trap)]);

 

 

% quad() ------------------------------------------------------------

% Next, we use the built-in function quad() to estimate the integral.

% This routine requires the user to supply a function that returns the

% value of f(x) given an input value of x.  For more detail on the

% operation of this function, consult the help page.

%

% quad() uses the following method to calculate the integral

%     - The domain [a,b] is divided into ever-smaller sub-intervalues

%       and the integrals over each sub-interval are added to return

%       the value of the integral over the entire domain [a,b].

%     - On each sub-interval, f(x) is approximated by using low-order

%       polynomial interpolation (linear, quadratic, etc.), and for

%       each interpolation polynomial, the value of the integral can

%       be calculated analytically.

%     - The estimated integral values for each order local polynomial

%       approximation are then combined in such a way that the low-order

%       (in Dx = the sub-interval size) contributions to the error

%       cancel out (Romberg integration)

%     - The routine iteratively refines the mesh until the estimated

%       error is below some specified tolerance.

%

% As a rule, quad() is recommended for functions that are not very smooth,

% as only low-order local approximations are used on each sub-interval.

 

% First, we demonstrate the use of quad where we supply the function

% explicitly through a character string.

tol = 1e-7;  % specify tolerance (default = 1e-6)

integral_quad_1 = quad(fun,a,b,tol);

disp(['Integral (quad w/ explicit function) = ', ...

        num2str(integral_quad_1)]);

 

% We can also use quad with an inline function.

integral_quad_2 = quad(F,a,b,tol);

disp(['Integral (quad w/ inline function) = ', ...

        num2str(integral_quad_2)]);

 

 

% For the development of programs, it is useful to be able to

% provide quad() with the name of a function that returns f(x)

% for an input x.  As an example, we will use a routine that

% return the value of f(x) = exp(-c*x.^2), where for our

% particular problem we will use a value of c=1.  The value of c

% for our problem is passed to the routine through the argument

% list of quad().  The name of the function to be evaluated is

% contained in the MATLAB file exp_sqr.m

%

% The contents of exp_sqr.m are

%   % ======================================================

%   % function f = exp_sqr(x,c);

%   %

%   % This routine returns, for input arguments of x (overloaded)

%   % and c, the values of exp(-c*x.^2).

%

%   function f = exp_sqr(x,c);

%

%   f = exp(-c*x.^2);

%

%   return;

 

fun_directory = pwd; % set directory name containing function

addpath(fun_directory); % add to path if not done so already

fun_name = 'exp_sqr';  % name of M-file containing function

c = 1;  % value of constant c for our problem

trace = [];  % if non-empty, quad() prints results of each iteration

integral_quad_3 = quad(fun_name,a,b,tol,trace,c);

disp(['Integral (quad w/ external routine) = ', ...

        num2str(integral_quad_3)]);

 

% We can also call quad() for a routine containined in the same

% m-file as our calling program when we know the name of the

% function.  As an example, we define exp_sqr_2() as a routine

% that performs exactly the same job as exp_sqr() but now add

% it to the calling M-file below.

integral_quad_4 = quad(@exp_sqr_2,a,b,tol,trace,c);

disp(['Integral (quad w/ named routine) = ', ...

        num2str(integral_quad_4)]);

 

 

% quadl() ----------------------------------------------------------

% In addition to quad(), MATLAB also includes the built-in function

% quadl() that uses Gauss-Lobatto quadrature (a modification of

% Gaussian quadrature) to evaluate the integral over each sub-interval.

% In Gauss-Lobatto quadrature, one places grid points at the zeros

% of the othogonal polynomial (that each satisfy a < xj < b, AND

% at one or both end points (a and/or b).

%

% quadl() gives higher-accuracy when the integrand f(x) varies smoothly

% and so can be approximated well locally by a low-order polynomial.

% For functions that are not smooth, quad() is recommended, since the

% higher-order local polynomial approximations used in quadl() may oscillate

% over sub-intervals containing rapid changes in f(x).

%

% We demonstrate the use of quadl with the routine exp_sqr_2.

integral_quadl_1 = quadl(@exp_sqr_2,a,b,tol,trace,c);

disp(['Integral (quadl w/ named routine) = ', ...

        num2str(integral_quadl_1)]);

 

% Now, let us say that we wish to integrate f(x), but only know

% the value of the function at a discrete set of grid points.

% We could use trapz(); however, this routine uses only a local

% linear interpolation, so that the method is not very accurate.

%

% We can use quadl() to obtain higher-order accuracy by using

% higher-order local approximations for f(x).  In the example

% below, we use the MATLAB built-in function interp1() to

% return the estimated value of f(x) by using the tabulated values

% of f and x and piecewise cubic spline interpolation.  Since

% this interpolation approximation for f(x) is everywhere a low-order

% polynomial locally, we expect quadl() to provide accurate results.

integral_spline = quadl(@cubic_interpolate,a,b,tol,trace, ...

    x_val,f_val);

disp(['Integral (quadl w/ spline interpolation) = ', ...

        num2str(integral_spline)]);

 

 

% ode15s() ---------------------------------------------------------

% Finally, we note that if we define the function y(x) as the integral

% from t = a to t = x of the function f(t), then we can obtain the

% value of the desired integral by solving the initial value problem

% y'(t) = f(t) with the initial contiion y(a) = 0.

%

% This method works if the function f(t) does not undergo singularities

% within [a,b], and can be quite efficient with an adaptive step-size

% algorithm for problems in which f(t) changes rapidly (but smoothly)

% over some region of [a,b].

%

% The built-in MATLAB function for solving initial value ODE problems,

% ode15s(), is used below to calculate the value of this integral.

t_span = [a b];

options = odeset('RelTol',1e-10,'AbsTol',1e-10);

[t_out,y_out] = ode15s(@exp_sqr_ode,t_span,0,options,c);

integral_ode15s = y_out(length(t_out));

disp(['Integral (ode15s) = ', ...

        num2str(integral_ode15s)]);

 

 

% gaussq() ----------------------------------------------------------

% While quad() and quadl() are standard functions in MATLAB, one can

% write MATLAB functions that perform Guassian quadrature in a more

% explicit format.  The MATLAB central file exchange at the URL :

%      www.mathworks.com/matlabcentral/fileexchange/index.jsp

% includes a routine gaussq (written by Per Brodtkorb) that performs

% Gaussian quadrature using the most-common orthogonal polynomials.

 

 

% Finally, we calculate the errors for each method.

disp(' ');

disp('Error magnitudes for each method');

% trapz()

error_trap = abs(integral_trap - integral_true);

disp(['Error (trapz) = ', ...

        num2str(error_trap)]);

% quad()

integral_quad_avg = ...

    mean([integral_quad_1,integral_quad_2,integral_quad_3]);

error_quad = abs(integral_quad_avg - integral_true);

disp(['Error (quad) = ', ...

        num2str(error_quad)]);

% quadl()

error_quadl = abs(integral_quadl_1 - integral_true);

disp(['Error (quadl) = ', ...

        num2str(error_quadl)]);

% spline interpolation of grid values

error_spline = abs(integral_spline - integral_true);

disp(['Error (quadl w/ spline interpolation) = ', ...

        num2str(error_spline)]);

% ode15s

error_ode15s = abs(integral_ode15s - integral_true);

disp(['Error (ode15s) = ', ...

        num2str(error_ode15s)]);

 

 

iflag_main = 1;

 

return;

 

 

 

% =========================================================

% function f = exp_sqr_2(x,c);

%

% This routine returns, for input arguments of x (overloaded) and c,

% the values of exp(-c*x.^2).

%

function f = exp_sqr_2(x,c);

 

f = exp(-c*x.^2);

 

return;

 

 

% ===========================================================

% function f = cubic_interpolate(x,x_val,f_val);

%

% This MATLAB function uses piecewise cubic spline interpolation

% to return a values of f(x) from tabulated values of f(x) at the

% grid points x_val that are stored in f_val.

%

% K. Beers. MIT ChE. 8/7/2002

 

function f = cubic_interpolate(x,x_val,f_val);

 

f = interp1(x_val,f_val,x,'spline');

 

return;

 

 

% =========================================================

% function f = exp_sqr_ode(x,y,c);

%

% This routine returns, for input arguments of x (overloaded) and c,

% the values of exp(-c*x.^2).  The value of y is the cumulative

% integral up to this point, and is not used to determine the value

% of f(x).

%

function f = exp_sqr_ode(x,y,c);

 

f = exp(-c*x.^2);

 

return;