function [u,utrue,errL2,errH1] = fem1d() % % program to solve the equation % % -d/dx(p(x)du/dx) + q(x)u = f % % with boundary conditions % % u(0) = u(pi) = 0 % % using the finite element method with piecewise linear % approximation functions. Uses functions p, q, and f % to evaluate coefficients and right-hand side. % % User is asked for the number of subintervals n. % Routine plots the true and computed solutions and their % difference. Returns the computed solution u, the true % solution utrue, the L2-norm of the error errL2, and the % H1-seminorm of the error errH1. % % Stiffness matrix is stored as a dense matrix and solved % using MATLAB operator "\". % n = input(' Enter number of subintervals: '); h = pi/n; % Loop over subintervals. Assemble global stiffness matrix A % and right-hand side vector b. A = zeros(n-1,n-1); b=zeros(n-1,1); for i=1:n, xim1 = (i-1)*h; xi = i*h; pt1 = (xi+xim1)/2 - h/(2*sqrt(3)); % pt1 and pt2 are the points used pt2 = (xi+xim1)/2 + h/(2*sqrt(3)); % in 2-point Gauss quadrature for % evaluating integrals % Stiffness matrix pint = .5*(p(pt1)+p(pt2))*h; qiint = .5*(q(pt1)*(pt1-xim1)^2 + q(pt2)*(pt2-xim1)^2)*h; qim1int = .5*(q(pt1)*(xi-pt1)^2 + q(pt2)*(xi-pt2)^2)*h; if i < n, A(i,i) = A(i,i) + pint/h^2 + qiint/h^2; end; if i > 1, A(i-1,i-1) = A(i-1,i-1) + pint/h^2 + qim1int/h^2; qiim1 = .5*h*(q(pt1)*(xi-pt1)*(pt1-xim1) + q(pt2)*(xi-pt2)*(pt2-xim1)); if i < n, A(i-1,i) = -pint/h^2 + qiim1/h^2; A(i,i-1) = A(i-1,i); end; end; % Right-hand side fiint = .5*(f(pt1)*(pt1-xim1) + f(pt2)*(pt2-xim1))*h; fim1int = .5*(f(pt1)*(xi-pt1) + f(pt2)*(xi-pt2))*h; if i < n, b(i) = b(i) + fiint/h; end; if i > 1, b(i-1) = b(i-1) + fim1int/h; end; end; % Solve linear system. u = A\b; % Plot true and approximate solutions and error. for i=1:n-1, xi = i*h; if xi <= pi/3, utrue(i,1) = sin(3*xi); end; if xi > pi/3, utrue(i,1) = .01*sin(3*xi); end; end; plot([h:h:pi-h]',u,'--', [h:h:pi-h]',utrue,'-') xlabel('x') ylabel('u(x)') title('True solution (solid) and approximate solution (dashed)') pause(5), plot([h:h:pi-h]',utrue-u,'-') xlabel('x') ylabel('error') title('Difference between true and computed solution') % Compute (approximate) L2-norm and H1-seminorm of error. errL2 = 0; errH1 = 0; for i=1:n, xim1 = (i-1)*h; xi = i*h; pt1 = (xi+xim1)/2 - h/(2*sqrt(3)); % pt1 and pt2 are the points used pt2 = (xi+xim1)/2 + h/(2*sqrt(3)); % in 2-point Gauss quadrature for % computing the error. if i > 1 & i < n, u_pt1 = u(i-1)*(xi-pt1)/h + u(i)*(pt1-xim1)/h; % Compute function u_pt2 = u(i-1)*(xi-pt2)/h + u(i)*(pt2-xim1)/h; % values and derivs uprime = (u(i)-u(i-1))/h; % for piecewise linear elseif i==1, % approximate solution u_pt1 = u(i)*(pt1-xim1)/h; % at pt1 and pt2. u_pt2 = u(i)*(pt2-xim1)/h; uprime = u(i)/h; elseif i==n, u_pt1 = u(i-1)*(xi-pt1)/h; u_pt2 = u(i-1)*(xi-pt2)/h; uprime = -u(i-1)/h; end; if pt1 <= pi/3, % Compute function utrue_pt1 = sin(3*pt1); % values and derivs utrueprime_pt1 = 3*cos(3*pt1); % for true solution else % at pt1 and pt2. utrue_pt1 = .01*sin(3*pt1); utrueprime_pt1 = .03*cos(3*pt1); end; if pt2 <= pi/3, utrue_pt2 = sin(3*pt2); utrueprime_pt2 = 3*cos(3*pt2); else utrue_pt2 = .01*sin(3*pt2); utrueprime_pt2 = .03*cos(3*pt2); end; errL2 = errL2 + h*.5*( (u_pt1 - utrue_pt1)^2 + (u_pt2 - utrue_pt2)^2 ); errH1 = errH1 + h*.5*( (uprime - utrueprime_pt1)^2 + ... (uprime - utrueprime_pt2)^2 ); end; errL2 = sqrt(errL2), errH1 = sqrt(errH1), % % Functions defining coefficients and right-hand side % function pval = p(x) if x <= pi/3, pval = 1; else pval = 100; end; return; function qval = q(x) qval = 1; return; function fval = f(x) sin3x = sin(3*x); fval = 9*sin3x; if x <= pi/3, fval = fval + sin3x; else fval = fval + .01*sin3x; end;