function y = sturm(X,BC,F,G,R)
% STURM  Solve the Sturm-Liouville equation:
%        d( F*dY/dX )/dX - G*Y = R using linear finite elements.
%
%        Y = STURM(X,BC,'F','G','R')
%
%        INPUT:
%        X  - a one-dimensional grid-point array of length N.
%        BC - is a 2 by 3 matrix [A1, B1, C1 ; An, Bn, Cn]
%             specifying the boundary conditions, which are of
%             the form: A1*Y'(1) + B1*Y(1) = C1 and
%             An*Y'(n) + Bn*Y(n) = Cn. Dirichlet boundary
%             conditions can be applied by setting A1 and/or An
%             to zero.
%        F(X), G(X) and R(X) are user-supplied functions. These
%        must be provided as separate M-files (F.M, G.M and R.M),
%        and must return an array of same shape and length as X.
%
%        The result can be displayed by: plot(X,Y).
%
% Alex Pletzer: pletzer@pppl.gov (Aug. 97/July 99).
%

[n1,n2] = size(X);
x = X(:);
n=length(x);    % # of f e
n1 = n-1;
x = sort(x);
xmin = x(1); xmax = x(n);
dx = diff(x); x = x(1:n1);

% boundary conditions

[nbc1,nbc2] = size(BC);
if ([nbc1 nbc2] ~= [2 3]),
        disp('Error calling STURM: Wrong format for BC specification')
        disp('the second argument must be a 2 times 3 matrix')
        disp('Homgeneous Dirichlet boundary conditions assumed')
        BC = [0 1 0;0 1 0]
end

if (BC(1,:) == [0 0 0]) | (BC(2,:) == [0 0 0]),
        disp('Error calling STURM: Null BC specification')
        BC
        disp('Homgeneous Dirichlet boundary conditions assumed')
        BC = [0 1 0;0 1 0]
end

a1 = BC(1,1); b1 = BC(1,2); c1 = BC(1,3);
an = BC(2,1); bn = BC(2,2); cn = BC(2,3);

% 3pt gauss' grid

abcis = [-0.77459666924148,0.0,+0.77459666924148];
abcis = (abcis+1)/2;
weigh = [0.5555555555556,0.88888888888889,0.55555555555556];
weigh = weigh/2;

x1 = x + dx*abcis(1);
x2 = x + dx*abcis(2);
x3 = x + dx*abcis(3);

xg = reshape( [conj(x1');conj(x2');conj(x3')],1,3*n1);

% f, g  and s functions

fg = feval(F,xg);
gg = feval(G,xg);
sg = feval(R,xg);


% construct matrices

fg = conj(reshape(fg,3,n1)');
gg = conj(reshape(gg,3,n1)');
sg = conj(reshape(sg,3,n1)');
g1 = gg(:,1); g2 = gg(:,2); g3 = gg(:,3);

% "kinetic"

k1 = (fg*weigh')./dx;
k1 = [0;k1]; k2 = k1(2:n);
k2 = [k2;0];
kd = k2 + k1;   % diagonal
ko = - k1(2:n); % diagonal-1
k = sparse( diag(kd) + diag(ko,-1) + diag(ko,+1) );

% "potential"

v1 = ( gg*conj(weigh.*abcis.^2)'         ).*dx; % / * /

v2 = ( gg*conj(weigh.*abcis.*(1-abcis))' ).*dx; % / * \

v3 = ( gg*conj(weigh.*(1-abcis).^2)'     ).*dx; % \ * \

v1 = [0;v1]; v3 = [v3;0];

vd = v1 + v3;
vo = v2;
v = sparse( diag(vd) + diag(vo,-1) + diag(vo,+1) );

% total

w = k + v;

% source

s1 = - ( sg*conj(weigh.*abcis)'         ).*dx; % /
s2 = - ( sg*conj(weigh.*(1-abcis))'     ).*dx; % \
s1 = [0;s1]; s2 = [s2;0];
s = s2 + s1;

% boundary conditions

        % left endpoint
        if a1 == 0,
                disp('Dirichlet BC at left endpoint:')
                disp(['y(1) = ',num2str(c1/b1)])
                w(1,:) = zeros(1,n); w(1,1)=1; s(1)=c1/b1;
        else
                disp('General BC at left endpoint:')
                disp(['y_x(1) + ',num2str(b1/a1),' y(1) = ',num2str(c1/a1)])
                w(1,1) = w(1,1) - b1/a1; s(1) = s(1) - c1/a1;
        end

        % right endpoint
        if an == 0,
                disp('Dirichlet BC at right endpoint:')
                disp(['y(n) = ',num2str(cn/bn)])
                w(n,:) = zeros(1,n); w(n,n)=1; s(n)=cn/bn;
        else
                disp('General BC at right endpoint:')
                disp(['y_x(n) + ',num2str(bn/an),' y(n) = ',num2str(cn/an)])
                w(n,n) = w(n,n) + bn/an; s(n) = s(n) + cn/an;
        end

% solve linear system

y=w\s;

[m1,m2] = size(y);
if (m1 == n2) & (m2 == n1), y = conj(y'); end
