Code covered by the BSD License  

Highlights from
bvp4c2

from bvp4c2 by Qun HAN
Faster version of the MATLAB function bvp4c.

bvp4c2(ode, bc, solinit, options, varargin)
function sol = bvp4c2(ode, bc, solinit, options, varargin)
%BVP4C  Solve boundary value problems for ODEs by collocation.
%   SOL = BVP4C(ODEFUN,BCFUN,SOLINIT) integrates a system of ordinary differential equations of the
%   form y' = f(x,y) on the interval [a,b], subject to general two-point boundary conditions of the
%   form bc(y(a),y(b)) = 0. ODEFUN and BCFUN are function handles. For a scalar X and a column
%   vector Y, ODEFUN(X,Y) must return a column vector representing f(x,y). For column vectors YA and
%   YB, BCFUN(YA,YB) must return a column vector representing bc(y(a),y(b)).  SOLINIT is a structure
%   with fields
%       x -- ordered nodes of the initial mesh with
%            SOLINIT.x(1) = a, SOLINIT.x(end) = b
%       y -- initial guess for the solution with SOLINIT.y(:,i)
%            a guess for y(x(i)), the solution at the node SOLINIT.x(i)
%
%   BVP4C produces a solution that is continuous on [a,b] and has a continuous first derivative
%   there. The solution is evaluated at points
%   XINT using the output SOL of BVP4C and the function DEVAL:
%   YINT = DEVAL(SOL,XINT). The output SOL is a structure with
%       SOL.x  -- mesh selected by BVP4C
%       SOL.y  -- approximation to y(x) at the mesh points of SOL.x
%       SOL.yp -- approximation to y'(x) at the mesh points of SOL.x
%       SOL.solver -- 'bvp4c'
%
%   SOL = BVP4C(ODEFUN,BCFUN,SOLINIT,OPTIONS) solves as above with default parameters replaced by
%   values in OPTIONS, a structure created with the BVPSET function. To reduce the run time greatly,
%   use OPTIONS to supply a function for evaluating the Jacobian and/or vectorize ODEFUN. See BVPSET
%   for details and SHOCKBVP for an example that does both.
%
%   Some boundary value problems involve a vector of unknown parameters p that must be computed
%   along with y(x):
%       y' = f(x,y,p)
%       0  = bc(y(a),y(b),p)
%   For such problems the field SOLINIT.parameters is used to provide a guess for the unknown
%   parameters. On output the parameters found are returned in the field SOL.parameters. The
%   solution SOL of a problem with one set of parameter values can be used as SOLINIT for another
%   set. Difficult BVPs may be solved by continuation: start with parameter values for which you can
%   get a solution, and use it as a guess for the solution of a problem with parameters closer to
%   the ones you want. Repeat until you solve the BVP for the parameters you want.
%
%   The function BVPINIT forms the guess structure in the most common situations:  SOLINIT =
%   BVPINIT(X,YINIT) forms the guess for an initial mesh X as described for SOLINIT.x, and YINIT
%   either a constant vector guess for the solution or a function handle. If YINIT is a function
%   handle then for a scalar X, YINIT(X) must return a column vector, a guess for the solution at
%   point x in [a,b]. If the problem involves unknown parameters SOLINIT = BVPINIT(X,YINIT,PARAMS)
%   forms the guess with the vector PARAMS of guesses for the unknown parameters.
%
%   BVP4C solves a class of singular BVPs, including problems with unknown parameters p, of the form
%       y' = S*y/x + f(x,y,p)
%       0  = bc(y(0),y(b),p)
%   The interval is required to be [0, b] with b > 0. Often such problems arise when computing a
%   smooth solution of ODEs that result from PDEs because of cylindrical or spherical symmetry. For
%   singular problems the (constant) matrix S is specified as the value of the 'SingularTerm' option
%   of BVPSET, and ODEFUN evaluates only f(x,y,p). The boundary conditions must be consistent with
%   the necessary condition S*y(0) = 0 and the initial guess should satisfy this condition.
%
%   BVP4C can solve multipoint boundary value problems.  For such problems there are boundary
%   conditions at points in [a,b]. Generally these points represent interfaces and provide a natural
%   division of [a,b] into regions. BVP4C enumerates the regions from left to right (from a to b),
%   with indices starting from 1.  In region k, BVP4C evaluates the derivative as YP =
%   ODEFUN(X,Y,K).  In the boundary conditions function, BCFUN(YLEFT,YRIGHT), YLEFT(:,K) is the
%   solution at the 'left' boundary of region k and similarly for YRIGHT(:,K).  When an initial
%   guess is created with BVPINIT(XINIT,YINIT), XINIT must have double entries for each interface
%   point. If YINIT is a function handle, BVPINIT calls Y = YINIT(X,K) to get an initial guess for
%   the solution at X in region k. In the solution structure SOL returned by BVP4C, SOL.x has double
%   entries for each interface point. The corresponding columns of SOL.y contain the 'left' and
%   'right' solution at the interface, respectively. See THREEBVP for an example of solving a
%   three-point BVP.
%
%   Example
%         solinit = bvpinit([0 1 2 3 4],[1 0]);
%         sol = bvp4c(@twoode,@twobc,solinit);
%     solve a BVP on the interval [0,4] with differential equations and boundary conditions computed
%     by functions twoode and twobc, respectively. This example uses [0 1 2 3 4] as an initial mesh,
%     and [1 0] as an initial approximation of the solution components at the mesh points.
%         xint = linspace(0,4);
%         yint = deval(sol,xint);
%     evaluate the solution at 100 equally spaced points in [0 4]. The first component of the
%     solution is then plotted with
%         plot(xint,yint(1,:));
%   For more examples see TWOBVP, FSBVP, SHOCKBVP, MAT4BVP, EMDENBVP, THREEBVP.
%
%   See also BVP5C, BVPSET, BVPGET, BVPINIT, BVPXTEND, DEVAL, FUNCTION_HANDLE.

%   BVP4C is a finite difference code that implements the 3-stage Lobatto IIIa formula. This is a
%   collocation formula and the collocation polynomial provides a C1-continuous solution that is
%   fourth order accurate uniformly in [a,b]. (For multipoint BVPs, the solution is C1-continuous
%   within each region, but continuity is not automatically imposed at the interfaces.) Mesh
%   selection and error control are based on the residual of the continuous solution. Analytical
%   condensation is used when the system of algebraic equations is formed.

%   Jacek Kierzenka and Lawrence F. Shampine
%   Copyright 1984-2008 The MathWorks, Inc.
%   $Revision: 1.21.4.16 $  $Date: 2008/05/23 15:35:05 $
%	Sparse construction optimized in "colloc_Jac",when there is no unknown parameters and FJacobian
%   is not used --------------junziyang

solver_name = 'bvp4c';

% Check input arguments
if nargin < 3
    error('MATLAB:bvp4c:NotEnoughInputs', 'Not enough input arguments.')
elseif nargin < 4
    options = [];
end

% Validate arguments and options
[n,npar,nregions,atol,rtol,Nmax,xyVectorized,printstats] = ...
    bvparguments(solver_name,ode,bc,solinit,options,varargin);

% Handle argument functions and additional arguments
[ode,bc,Fjac,BCjac,Joptions,dBCoptions] = ...
    bvpfunctions(solver_name,ode,bc,options,n,npar,nregions,varargin);

% Deal with a singular BVP.
[singularBVP,ode,Fjac,solinit,PBC] = ...
    bvpsingular(solver_name,solinit,ode,Fjac,options,n,npar,nregions);

% Adjust function arguments to accommodate unknown parameters
unknownPar = (npar > 0);
ExtraArgs = {};
if unknownPar
    ExtraArgs = [ExtraArgs,solinit.parameters(:)];
end
nExtraArgs = length(ExtraArgs);

threshold = atol/rtol;

% Initialize counters (count test calls in BVPARGUMENTS)
nODEeval = 1;
nBCeval = 1;

% Mesh and solution at mesh points
x = solinit.x(:)';  % row vector
y = solinit.y;
N = length(x);      % number of mesh points
nN = n*N;

% Recognize a multipoint BVP
nBCs = n * nregions + npar;
mbcidx = find(diff(x) == 0);  % locate internal interfaces

% Input to ODENUMJAC for vectorized problems
vectVars = [];
if xyVectorized
    vectVars = [1,2];
end

% Algebraic solver parameters
maxNewtIter = 4;
maxProbes = 4;    % weak line search
needGlobJac = true;

meshHistory = [0,0];            % Keep track of [N, maxres],
residualReductionGuard = 1e-4;  % to prevent mesh oscillations.

done = false;

% THE MAIN LOOP:
while ~done
    
    if unknownPar
        Y = [y(:);ExtraArgs{1}];
    else
        Y =  y(:);
    end
    
    [RHS,yp,Fmid,NF] = colloc_RHS(n,x,Y,ode,bc,npar,xyVectorized,mbcidx,nExtraArgs,ExtraArgs);
    nODEeval = nODEeval + NF;
    nBCeval = nBCeval + 1;
    
    for iter=1:maxNewtIter
        if needGlobJac
            % setup and factor the global Jacobian
            [dPHIdy,NF,NBC] = colloc_Jac(n,x,Y,yp,Fmid,ode,bc,Fjac,Joptions,BCjac,dBCoptions,...
                npar,vectVars,mbcidx,nExtraArgs,ExtraArgs);
            needGlobJac = false;
            nODEeval = nODEeval + NF;
            nBCeval = nBCeval + NBC;
            % explicit row scaling
            wt = max(abs(dPHIdy),[],2);
            if any(wt == 0) || ~all(isfinite(nonzeros(dPHIdy)))
                singJac = true;
            else
                scalMatrix = spdiags(1 ./ wt,0,nN+npar,nN+npar);
                dPHIdy = scalMatrix * dPHIdy;
% 				tic
                [L,U,P,Q,R] = lu(dPHIdy);
% 				toc
% 				tic
%%	UMFPACK2 ЧLUԱ'Sparse Lu with 4 outputs(UMFPACK) failed' , Out of memory.
% 				[L,U,P,Q,R] = umfpack2(dPHIdy); %From SuiteSparse -----------------------------------junziyang GoToBLASŻ
% 				toc
% 				1
                singJac = bvpcheckmatrix(dPHIdy,L,U,P,Q,R);
            end
            if singJac
                error('MATLAB:bvp4c:SingJac', '%s -- %s', ...
                    'Unable to solve the collocation equations', ...
                    'a singular Jacobian encountered');
            end
        end
        
        % find the Newton direction
        delY = Q * (U \ (L \ (P * (R \ ( scalMatrix * RHS)))));
        distY = norm(delY);
        
        % weak line search with an affine stopping criterion
        lambda = 1;
        for probe = 1:maxProbes
            Ynew = Y - lambda*delY;
            
            if singularBVP     % Impose necessary BC, Sy(0) = 0.
                Ynew(1:n) = PBC*Ynew(1:n);
            end
            
            if unknownPar
                ExtraArgs{1} = Ynew(nN+1:end);
            end
            
            [RHS,yp,Fmid,NF] = colloc_RHS(n,x,Ynew,ode,bc,npar,xyVectorized,mbcidx,nExtraArgs,ExtraArgs);
            
            nODEeval = nODEeval + NF;
            nBCeval = nBCeval + 1;
            
            distYnew = norm(U \ (L \ (P * (R \ (scalMatrix * RHS)))));
            
            if (distYnew < 0.9*distY)
                break
            else
                lambda = 0.5*lambda;
            end
        end
        
        needGlobJac = (distYnew > 0.1*distY);
        
        if distYnew < 0.1*rtol
            break
        else
            Y = Ynew;
        end
    end
    
    y = reshape(Ynew(1:nN),n,N); % yp, ExtraArgs, and RHS are consistent with y
    
    [res,NF] = residual(ode,x,y,yp,Fmid,RHS,threshold,xyVectorized,nBCs, ...
        mbcidx,ExtraArgs);
    nODEeval = nODEeval + NF;
    
    maxres = max(res);
    if maxres < rtol
        done = true;
        
    else 	% redistribute the mesh
        
        % Detect mesh oscillations:  Was there a mesh with
        % the same number of nodes and a similar residual?
        idx = find(meshHistory(:,1) == N);
        residualReduction = abs(meshHistory(idx,2) - maxres)/maxres;
        oscLikely = any( residualReduction < residualReductionGuard);
        
        % modify the mesh, interpolate the solution
        meshHistory(end+1,:) = [N,maxres];
        canRemovePoints = ~oscLikely;
        [N,x,y,mbcidx] = new_profile(n,x,y,yp,res,mbcidx,rtol,Nmax,canRemovePoints);
        
        if N > Nmax
            warning('MATLAB:bvp4c:RelTolNotMet', ...
                [ 'Unable to meet the tolerance without using more than %d '...
                'mesh points. \n The last mesh of %d points and ' ...
                'the solution are available in the output argument. \n ', ...
                'The maximum residual is %g, while requested accuracy is %g.'], ...
                Nmax,length(x),max(res),rtol);
            sol.x = x;
            sol.y = y;
            sol.yp = yp;
            sol.solver = solver_name;
            if unknownPar
                sol.parameters = ExtraArgs{1};
            end
            return
        end
        
        nN = n*N;
        
        needGlobJac = true;
        
    end
    
end    % while

% Output
sol.x = x;
sol.y = y;
sol.yp = yp;
sol.solver = solver_name;
if unknownPar
    sol.parameters = ExtraArgs{1};
end

% Stats
if printstats
    fprintf('The solution was obtained on a mesh of %g points.\n',N);
    fprintf('The maximum residual is %10.3e. \n',max(res));
    fprintf('There were %g calls to the ODE function. \n',nODEeval);
    fprintf('There were %g calls to the BC function. \n',nBCeval);
end

%---------------------------------------------------------------------------

function [Sx,Spx] = interp_Hermite (hnode,diffx,y,yp)
%INTERP_HERMITE  Evaluate the cubic Hermite interpolant and its first
%   derivative at x+hnode*diffx.
N = size(y,2);
diffx = diffx(:);  % column vector
diagscal = spdiags(1./diffx,0,N-1,N-1);
slope = (y(:,2:N) - y(:,1:N-1)) * diagscal;
c = (3*slope - 2*yp(:,1:N-1) - yp(:,2:N)) * diagscal;
d = (yp(:,1:N-1)+yp(:,2:N)-2*slope) * (diagscal.^2);

diagscal = spdiags(hnode*diffx,0,diagscal);
d = d*diagscal;

Sx = ((d+c)*diagscal+yp(:,1:N-1))*diagscal+y(:,1:N-1);
Spx = (3*d+2*c)*diagscal+yp(:,1:N-1);

%---------------------------------------------------------------------------

function [res,nfcn] = residual (Fcn, x, y, yp, Fmid, RHS, threshold, ...
    xyVectorized, nBCs, mbcidx, ExtraArgs)
%RESIDUAL  Compute L2-norm of the residual using 5-point Lobatto quadrature.

% multi-point BVP support
ismbvp = ~isempty(mbcidx);
nregions = length(mbcidx) + 1;
Lidx = [1, mbcidx+1];
Ridx = [mbcidx, length(x)];
if ismbvp
    FcnArgs = {0,ExtraArgs{:}};  % pass region idx
else
    FcnArgs = ExtraArgs;
end

% Lobatto quadrature
lob4 = (1+sqrt(3/7))/2;
lob2 = (1-sqrt(3/7))/2;
lobw24 = 49/90;
lobw3 = 32/45;

[n,N] = size(y);

res = [];
nfcn = 0;

% Residual at the midpoints is related to the error
% in satisfying the collocation equations.
NewtRes = zeros(n,N-1);
% Do not populate the interface intervals for multi-point BVPs.
intidx = setdiff(1:N-1,mbcidx);
NewtRes(:,intidx) = reshape(RHS(nBCs+1:end),n,[]);

for region = 1:nregions
    if ismbvp
        FcnArgs{1} = region;    % Pass the region index to the ODE function.
    end
    
    xidx = Lidx(region):Ridx(region);    % mesh point index
    Nreg = length(xidx);
    xreg = x(xidx);
    yreg = y(:,xidx);
    ypreg = yp(:,xidx);
    hreg = diff(xreg);
    
    iidx = xidx(1:end-1);   % mesh interval index
    Nint = length(iidx);
    
    thresh = threshold(:,ones(1,Nint));
    
    % the mid-points
    temp =  (NewtRes(:,iidx) * spdiags(1.5./hreg(:),0,Nint,Nint)) ./ ...
        max(abs(Fmid(:,iidx)),thresh);
    res_reg = lobw3*dot(temp,temp,1);
    
    % Lobatto L2 points
    xLob = xreg(1:Nreg-1) + lob2*hreg;
    [yLob,ypLob] = interp_Hermite(lob2,hreg,yreg,ypreg);
    if xyVectorized
        fLob = Fcn(xLob,yLob,FcnArgs{:});
        nfcn = nfcn + 1;
    else
        fLob = zeros(n,Nint);
        for i = 1:Nint
            fLob(:,i) = Fcn(xLob(i),yLob(:,i),FcnArgs{:});
        end
        nfcn = nfcn + Nint;
    end
    temp = (ypLob - fLob) ./ max(abs(fLob),thresh);
    resLob = dot(temp,temp,1);
    res_reg = res_reg + lobw24*resLob;
    
    % Lobatto L4 points
    xLob = xreg(1:Nreg-1) + lob4*hreg;
    [yLob,ypLob] = interp_Hermite(lob4,hreg,yreg,ypreg);
    if xyVectorized
        fLob = Fcn(xLob,yLob,FcnArgs{:});
        nfcn = nfcn + 1;
    else
        for i = 1:Nint
            fLob(:,i) = Fcn(xLob(i),yLob(:,i),FcnArgs{:});
        end
        nfcn = nfcn + Nint;
    end
    temp = (ypLob - fLob) ./ max(abs(fLob),thresh);
    resLob = dot(temp,temp,1);
    res_reg = res_reg + lobw24*resLob;
    
    % scaling
    res_reg = sqrt( abs(hreg/2) .* res_reg);
    
    res(iidx) = res_reg;
end


%---------------------------------------------------------------------------

function [NN,xx,yy,mbcidxnew] = new_profile(n,x,y,yp,res,mbcidx,rtol,Nmax,canRemovePoints)
%NEW_PROFILE  Redistribute mesh points and approximate the solution.

% multi-point BVP support
nregions = length(mbcidx) + 1;
Lidx = [1, mbcidx+1];
Ridx = [mbcidx, length(x)];

mbcidxnew = [];

xx = [];
yy = [];
NN = 0;

for region = 1:nregions
    
    xidx = Lidx(region):Ridx(region);  % mesh point index
    xreg = x(xidx);
    yreg = y(:,xidx);
    ypreg = yp(:,xidx);
    hreg = diff(xreg);
    Nreg = length(xidx);
    
    iidx = xidx(1:end-1);    % mesh interval index
    resreg = res(iidx);
    i1 = find(resreg > rtol);
    i2 = find(resreg(i1) > 100*rtol);
    NNmax = Nreg + length(i1) + length(i2);
    xxreg = zeros(1,NNmax);
    yyreg = zeros(n,NNmax);
    last_int = Nreg - 1;
    
    xxreg(1) = xreg(1);
    yyreg(:,1) = yreg(:,1);
    NNreg = 1;
    i = 1;
    while i <= last_int
        if resreg(i) > rtol     % introduce points
            if resreg(i) > 100*rtol
                Ni = 2;
            else
                Ni = 1;
            end
            hi = hreg(i) / (Ni+1);
            j = 1:Ni;
            xxreg(NNreg+j) = xxreg(NNreg) + j*hi;
            yyreg(:,NNreg+j) = ntrp3h(xxreg(NNreg+j),xreg(i),yreg(:,i),xreg(i+1),...
                yreg(:,i+1),ypreg(:,i),ypreg(:,i+1));
            NNreg = NNreg + Ni;
        else
            if canRemovePoints && (i <= last_int-2) && all(resreg(i+1:i+2) < rtol)
                % try removing points
                hnew = (hreg(i)+hreg(i+1)+hreg(i+2))/2;
                C1 = resreg(i)/(hreg(i)/hnew)^(7/2);
                C2 = resreg(i+1)/(hreg(i+1)/hnew)^(7/2);
                C3 = resreg(i+2)/(hreg(i+2)/hnew)^(7/2);
                pred_res = max([C1,C2,C3]);
                
                if pred_res < 0.5 * rtol   % replace 3 intervals with 2
                    xxreg(NNreg+1) = xxreg(NNreg) + hnew;
                    yyreg(:,NNreg+1) = ntrp3h(xxreg(NNreg+1),xreg(i+1),yreg(:,i+1),xreg(i+2),...
                        yreg(:,i+2),ypreg(:,i+1),ypreg(:,i+2));
                    NNreg = NNreg + 1;
                    i = i + 2;
                end
            end
        end
        NNreg = NNreg + 1;
        xxreg(NNreg) = xreg(i+1);   % preserve the next mesh point
        yyreg(:,NNreg) = yreg(:,i+1);
        i = i + 1;
    end
    
    NN = NN + NNreg;
    if (NN > Nmax)
        % return the previous solution
        xx = x;
        yy = y;
        mbcidxnew = mbcidx;
        break
    else
        xx = [xx, xxreg(1:NNreg)];
        yy = [yy, yyreg(:,1:NNreg)];
        if region < nregions    % possible only for multipoint BVPs
            mbcidxnew = [mbcidxnew, NN];
        end
    end
end


%---------------------------------------------------------------------------

function [Phi,F,Fmid,nfcn] = colloc_RHS(n, x, Y, Fcn, Gbc, npar, xyVectorized, ...
    mbcidx, nExtraArgs, ExtraArgs)
%COLLOC_RHS  Evaluate the system of collocation equations Phi(Y).
%   The derivative approximated at the midpoints and returned in Fmid is
%   used to estimate the residual.

% multi-point BVP support
ismbvp = ~isempty(mbcidx);
nregions = length(mbcidx) + 1;
Lidx = [1, mbcidx+1];
Ridx = [mbcidx, length(x)];
if ismbvp
    FcnArgs = {0,ExtraArgs{:}};    % Pass the region index to the ODE function.
else
    FcnArgs = ExtraArgs;
end

y = reshape(Y(1:end-npar),n,[]);

[n,N] = size(y);
nBCs = n*nregions + npar;

F = zeros(n,N);
Fmid = zeros(n,N-1);    % include interface intervals
Phi = zeros(nBCs+n*(N-nregions),1);    % exclude interface intervals

% Boundary conditions
% Do not pass info about singular BVPs in ExtraArgs to BC function.
Phi(1:nBCs) = Gbc(y(:,Lidx),y(:,Ridx),ExtraArgs{1:nExtraArgs});
phiptr = nBCs;    % active region of Phi

for region = 1:nregions
    if ismbvp
        FcnArgs{1} = region;
    end
    xidx = Lidx(region):Ridx(region);   % mesh point index
    Nreg = length(xidx);
    xreg = x(xidx);
    yreg = y(:,xidx);
    
    iidx = xidx(1:end-1);   % mesh interval index
    Nint = length(iidx);
    
    % derivative at the mesh points
    if xyVectorized
        Freg = Fcn(xreg,yreg,FcnArgs{:});
        nfcn = 1;
    else
        Freg = zeros(n,Nreg);
        for i = 1:Nreg
            Freg(:,i) = Fcn(xreg(i),yreg(:,i),FcnArgs{:});
        end
        nfcn = Nreg;
    end
    
    % derivative at the midpoints
    h = diff(xreg);
    H = spdiags(h(:),0,Nint,Nint);
    xi = xreg(1:end-1);
    yi = yreg(:,1:end-1);
    xip1 = xreg(2:end);
    yip1 = yreg(:,2:end);
    Fi = Freg(:,1:end-1);
    Fip1 = Freg(:,2:end);
    
    xip05 = (xi + xip1)/2;
    yip05 = (yi + yip1)/2 - (Fip1 - Fi)*(H/8);
    if xyVectorized
        Fip05 = Fcn(xip05,yip05,FcnArgs{:});
        nfcn = nfcn + 1;
    else % not vectorized
        Fip05 = zeros(n,Nint);
        for i = 1:Nint
            Fip05(:,i) = Fcn(xip05(i),yip05(:,i),FcnArgs{:});
        end
        nfcn = nfcn + Nint;
    end
    
    % the Lobatto IIIa formula
    Phireg = yip1 - yi - (Fip1 + 4*Fip05 + Fi)*(H/6);
    
    % output assembly
    Phi(phiptr+1:phiptr+n*Nint) = Phireg(:);
    F(:,xidx) = Freg;
    Fmid(:,iidx) = Fip05;
    phiptr = phiptr + n*Nint;
    
end

%---------------------------------------------------------------------------

function [dPHIdy,nfcn,nbc] = colloc_Jac(n, x, Y, F, Fmid, ode, bc, ...
    Fjac, Joptions, BCjac, dBCoptions, ...
    npar, vectVars, mbcidx, nExtraArgs, ExtraArgs)
%COLLOC_JAC  Form the global Jacobian of collocation eqns.

% multi-point BVP support
ismbvp = ~isempty(mbcidx);
nregions = length(mbcidx) + 1;
Lidx = [1, mbcidx+1];
Ridx = [mbcidx, length(x)];
if ismbvp
    FcnArgs = {0,ExtraArgs{:}};  % pass region idx
else
    FcnArgs = ExtraArgs;
end
N = length(x);
nN = n*N;
intyp = uinttype(nN); %Determains the proper unit** type for cow & rol------------------------------junziyang
In = eye(n);

nfcn = 0;
nbc = 0;

y = reshape(Y(1:nN),n,N);

% BC points
ya = y(:,Lidx);
yb = y(:,Ridx);

if isempty(Fjac)  % use numerical approx
    if npar > 0   % unknown parameters
        threshval = 1e-6;
        if ismbvp
            dPoptions.diffvar = 4;  % dF(x,y,region,p)/dp
        else
            dPoptions.diffvar = 3;  % dF(x,y,p)/dp
        end
        dPoptions.vectvars = vectVars;
        dPoptions.thresh = threshval(ones(npar,1));
        dPoptions.fac = [];
    end
end

% Collocation equations
nBCs = n*nregions + npar;

rows = nBCs+1:nBCs+n;   % define the action area
cols = 1:n;             % in the global Jacobian

if npar == 0   % no unknown parameters
    if ~isempty(Fjac)  % ----------------------------------------------------------------------------junziyang
		dPHIdy = spalloc(nN,nN,2*n*nN);  % sparse storage
    end % -------------------------------------------------------------------------------------------junziyang
    if isempty(BCjac)   % use numerical approx
        [dGdya,dGdyb,nbc] = BCnumjac(bc,ya,yb,n,npar,dBCoptions,nExtraArgs,ExtraArgs);
    elseif iscell(BCjac)     % Constant partial derivatives {dGdya,dGdyb}
        dGdya = BCjac{1};
        dGdyb = BCjac{2};
    else  % use analytical Jacobian
        [dGdya,dGdyb] = BCjac(ya,yb,ExtraArgs{1:nExtraArgs});
    end
    
    % Collocation equations
    for region = 1:nregions
        
        if ~isempty(Fjac)  % ------------------------------------------------------------------------junziyang
            % Left BC
            dPHIdy(1:nBCs,cols) = dGdya(:,(region-1)*n+(1:n));
        end %----------------------------------------------------------------------------------------junziyang
        if  ismbvp
            FcnArgs{1} = region; % Pass the region index to the ODE function.
        end
        
        xidx = Lidx(region):Ridx(region);    % mesh point index
        xreg = x(xidx);
        yreg = y(:,xidx);
        Freg = F(:,xidx);
        hreg = diff(xreg);
        
        iidx = xidx(1:end-1);    % mesh interval index
        Nint = length(iidx);
        Fmidreg = Fmid(:,iidx);
        
        % Collocation equations
        if isempty(Fjac)  % use numerical approx
            
            Joptions.fac = [];
            [Ji,Joptions.fac,ignored,nFcalls] = ...
                odenumjac(ode,{xreg(1),yreg(:,1),FcnArgs{:}},Freg(:,1),Joptions);
            nfcn = nfcn+nFcalls;
            nrmJi = norm(Ji,1);
            %----------------------------------------------------------------------------------------junziyang
            numval=2*n*(n*Nint+1);
            val = zeros(numval,1);%------------------------------------------------------------------junziyang
            row = zeros(numval,1,intyp);%------------------------------------------------------------junziyang
            col = zeros(numval,1,intyp);%------------------------------------------------------------junziyang
            row(1:n)=1:n;%---------------------------------------------------------------------------junziyang
            col(1:n)=1:n;%---------------------------------------------------------------------------junziyang
            tmp=diag(dGdya(:,(region-1)*n+(1:n)));%--------------------------------------------------junziyang
            val(1:n)=tmp(:);%------------------------------------------------------------------------junziyang
            nval1=n;%--------------------------------------------------------------------------------junziyang
            %----------------------------------------------------------------------------------------junziyang
            for i = 1:Nint
                % the left mesh point
                xi = xreg(i);
                yi = yreg(:,i);
                Fi = Freg(:,i);
                % the right mesh point
                xip1 = xreg(i+1);
                yip1 = yreg(:,i+1);
                Fip1 = Freg(:,i+1);
                [Jip1,Joptions.fac,ignored,nFcalls] = ...
                    odenumjac(ode,{xip1,yip1,FcnArgs{:}},Fip1,Joptions);
                nfcn = nfcn + nFcalls;
                nrmJip1 = norm(Jip1,1);
                
                % the midpoint
                hi = hreg(i);
				xip05 = (xi + xip1)/2;
				if norm(Jip1 - Ji,1) <= 0.25*(nrmJi + nrmJip1)
					twiceJip05 = Ji + Jip1;
				else
					yip05 = (yi + yip1)/2 - hi/8*(Fip1 - Fi);
					Fip05 = Fmidreg(:,i);
					[Jip05,Joptions.fac,ignored,nFcalls] = ...
						odenumjac(ode,{xip05,yip05,FcnArgs{:}},Fip05,Joptions);
					nfcn = nfcn + nFcalls;
					twiceJip05 = 2*Jip05;
				end
				hi_4=0.25*hi;%hi/4
				hi_6=hi/6; %hi/6
                % assembly
                nval2=nval1+n*n;%--------------------------------------------------------------------junziyang
                row(nval1+1:nval2)=repmat(rows,1,n);%------------------------------------------------junziyang
                temp=repmat(cols,n,1);%--------------------------------------------------------------junziyang
                col(nval1+1:nval2)=temp(:);%---------------------------------------------------------junziyang
                temp = -(In+hi_6*(Ji+twiceJip05*(In+hi_4*Ji)));%-------------------------------------junziyang
                val(nval1+1:nval2)=temp(:);%---------------------------------------------------------junziyang
                nval1=nval2;%------------------------------------------------------------------------junziyang
                cols = cols + n;%--------------------------------------------------------------------junziyang
                nval2=nval1+n*n;%--------------------------------------------------------------------junziyang
                row(nval1+1:nval2)=repmat(rows,1,n);%------------------------------------------------junziyang
                temp=repmat(cols,n,1);%--------------------------------------------------------------junziyang
                col(nval1+1:nval2)=temp(:);%---------------------------------------------------------junziyang
                temp = In-hi_6*(Jip1+twiceJip05*(In-hi_4*Jip1));%------------------------------------junziyang
                val(nval1+1:nval2)=temp(:);%---------------------------------------------------------junziyang
                nval1=nval2;%------------------------------------------------------------------------junziyang
                rows = rows+n;%----------------------------------------------------------------------junziyang
                %dPHIdy(rows,cols) = -(In+hi/6*(Ji+twiceJip05*(In+hi/4*Ji)));%-----------------------Mathworks
                %cols = cols +n;%--------------------------------------------------------------------Mathworks
                %dPHIdy(rows,cols) = In-hi/6*(Jip1+twiceJip05*(In-hi/4*Jip1));%----------------------Mathworks
                %rows = rows+n;   % next equation%---------------------------------------------------Mathworks
                Ji = Jip1;
                nrmJi = nrmJip1;
            end
            
        elseif isnumeric(Fjac) % constant Jacobian
            J = Fjac(:,(region-1)*n+(1:n));
            J2 = J*J;
            for i = 1:Nint
                h2J   = hreg(i)/2*J;
                h12J2 = hreg(i)^2/12*J2;
                dPHIdy(rows,cols) = -(In+h2J+h12J2);
                cols = cols + n;
                dPHIdy(rows,cols) =   In-h2J+h12J2;
                rows = rows+n;   % next equation
            end
            
        else % use analytical Jacobian
            
            Ji = Fjac(xreg(:,1),yreg(:,1),FcnArgs{:});
            
            for i = 1:Nint
                % the left mesh point
                xi = xreg(i);
                yi = yreg(:,i);
                Fi = Freg(:,i);
                % the right mesh point
                xip1 = xreg(i+1);
                yip1 = yreg(:,i+1);
                Fip1 = Freg(:,i+1);
                Jip1 = Fjac(xip1,yip1,FcnArgs{:});
                % the midpoint
                hi = hreg(i);
                xip05 = (xi + xip1)/2;
                yip05 = (yi + yip1)/2 - hi/8*(Fip1 - Fi);
                Jip05 = Fjac(xip05,yip05,FcnArgs{:});  % recompute the Jacobian
                twiceJip05 = 2*Jip05;
                % assembly
                dPHIdy(rows,cols) = -(In+hi/6*(Ji+twiceJip05*(In+hi/4*Ji)));
                cols = cols + n;
                dPHIdy(rows,cols) = In-hi/6*(Jip1+twiceJip05*(In-hi/4*Jip1));
                rows = rows + n;   % next equation
                
                Ji = Jip1;
            end
        end
        
        if ~isempty(Fjac)  % ------------------------------------------------------------------------junziyang
            % Right BC
            dPHIdy(1:nBCs,cols) = dGdyb(:,(region-1)*n+(1:n));
        else% ---------------------------------------------------------------------------------------junziyang
            nval2=nval1+n;
            row(nval1+1:nval2)=1:nBCs;%--------------------------------------------------------------junziyang
            col(nval1+1:nval2)=cols;%----------------------------------------------------------------junziyang
            tmp=diag(dGdyb(:,(region-1)*n+(1:n)));%--------------------------------------------------junziyang
            val(nval1+1:nval2)=tmp(:);%--------------------------------------------------------------junziyang
            nval1=nval2;
% 			tic
%             dPHIdy=sparse(row,col,val,nN,nN);
% 		   toc
% 		   tic
			dPHIdy=sparse2(row,col,val,nN,nN); %sparse from SuiteSparse -----------------------------junziyang
% 			toc
        end% ----------------------------------------------------------------------------------------junziyang
        
        cols = cols + n;
        
    end % regions
    
else  % there are unknown parameters
    
    dPHIdy = spalloc(nN+npar,nN+npar,(nN+npar)*(2*n+npar));  % sparse storage
    last_cols = zeros(nN+npar,npar);   % accumulator
    
    if isempty(BCjac)   % use numerical approx
        [dGdya,dGdyb,nbc,dGdpar] = BCnumjac(bc,ya,yb,n,npar,dBCoptions,nExtraArgs,ExtraArgs);
    elseif iscell(BCjac)     % Constant partial derivatives {dGdya,dGdyb}
        dGdya  = BCjac{1};
        dGdyb  = BCjac{2};
        dGdpar = BCjac{3};
    else  % use analytical Jacobian
        [dGdya,dGdyb,dGdpar] = BCjac(ya,yb,ExtraArgs{1:nExtraArgs});
    end
    last_cols(1:nBCs,:) = dGdpar;
    
    % Collocation equations
    for region = 1:nregions
        
        % Left BC
        dPHIdy(1:nBCs,cols) = dGdya(:,(region-1)*n+(1:n));
        
        if ismbvp
            FcnArgs{1} = region;
        end
        
        xidx = Lidx(region):Ridx(region);
        xreg = x(xidx);
        yreg = y(:,xidx);
        Freg = F(:,xidx);
        hreg = diff(xreg);
        
        iidx = xidx(1:end-1);    % mesh interval index
        Nint = length(iidx);
        Fmidreg = Fmid(:,iidx);
        
        % Collocation equations
        if isempty(Fjac)  % use numerical approx
            
            Joptions.fac = [];
            dPoptions.fac = [];
            [Ji,Joptions.fac,dFdpar_i,dPoptions.fac,nFcalls] = ...
                Fnumjac(ode,{xreg(1),yreg(:,1),FcnArgs{:}},Freg(:,1),...
                Joptions,dPoptions);
            nfcn = nfcn+nFcalls;
            nrmJi = norm(Ji,1);
            nrmdFdpar_i = norm(dFdpar_i,1);
            
            for i = 1:Nint
                % the left mesh point
                xi = xreg(i);
                yi = yreg(:,i);
                Fi = Freg(:,i);
                % the right mesh point
                xip1 = xreg(i+1);
                yip1 = yreg(:,i+1);
                Fip1 = Freg(:,i+1);
                [Jip1,Joptions.fac,dFdpar_ip1,dPoptions.fac,nFcalls] = ...
                    Fnumjac(ode,{xip1,yip1,FcnArgs{:}},Fip1,Joptions,dPoptions);
                nfcn = nfcn + nFcalls;
                nrmJip1 = norm(Jip1,1);
                nrmdFdpar_ip1 = norm(dFdpar_ip1,1);
                % the midpoint
                hi = hreg(i);
                xip05 = (xi + xip1)/2;
                if (norm(Jip1 - Ji,1) <= 0.25*(nrmJi + nrmJip1)) && ...
                        (norm(dFdpar_ip1 - dFdpar_i,1) <= 0.25*(nrmdFdpar_i + nrmdFdpar_ip1))
                    Jip05 = 0.5*(Ji + Jip1);
                    dFdpar_ip05 = 0.5*(dFdpar_i + dFdpar_ip1);
                else
                    yip05 = (yi+yip1)/2-hi/8*(Fip1-Fi);
                    Fip05 = Fmidreg(:,i);
                    [Jip05,Joptions.fac,dFdpar_ip05,dPoptions.fac,nFcalls] = ...
                        Fnumjac(ode,{xip05,yip05,FcnArgs{:}},Fip05,Joptions,dPoptions);
                    nfcn = nfcn + nFcalls;
                end
                twiceJip05 = 2*Jip05;
                % assembly
                dPHIdy(rows,cols) = -(In+hi/6*(Ji+twiceJip05*(In+hi/4*Ji)));
                cols = cols + n;
                dPHIdy(rows,cols) = In-hi/6*(Jip1+twiceJip05*(In-hi/4*Jip1));
                last_cols(rows,:) = -hi*dFdpar_ip05 + hi^2/12*Jip05*...
                    (dFdpar_ip1-dFdpar_i);
                rows = rows+n;   % next equation
                
                Ji = Jip1;
                nrmJi = nrmJip1;
                dFdpar_i = dFdpar_ip1;
                nrmdFdpar_i = nrmdFdpar_ip1;
            end
            
        elseif iscell(Fjac)     % Constant partial derivatives {dFdY,dFdp}
            J = Fjac{1}(:,(region-1)*n+(1:n));
            dFdp = Fjac{2}(:,(region-1)*npar+(1:npar));
            J2 = J*J;
            for i = 1:Nint
                h2J   = hreg(i)/2*J;
                h12J2 = hreg(i)^2/12*J2;
                dPHIdy(rows,cols) = -(In+h2J+h12J2);
                cols = cols + n;
                dPHIdy(rows,cols) =   In-h2J+h12J2;
                
                last_cols(rows,:) = -hreg(i)*dFdp;
                
                rows = rows+n;   % next equation
            end
            
        else % use analytical Jacobian
            
            [Ji,dFdpar_i] = Fjac(xreg(1),yreg(:,1),FcnArgs{:});
            
            for i = 1:Nint
                % the left mesh point
                xi = xreg(i);
                yi = yreg(:,i);
                Fi = Freg(:,i);
                % the right mesh point
                xip1 = xreg(i+1);
                yip1 = yreg(:,i+1);
                Fip1 = Freg(:,i+1);
                [Jip1, dFdpar_ip1] = Fjac(xip1,yip1,FcnArgs{:});
                % the midpoint
                hi = hreg(i);
                xip05 = (xi + xip1)/2;
                yip05 = (yi + yip1)/2 - hi/8*(Fip1 - Fi);
                [Jip05, dFdpar_ip05] = Fjac(xip05,yip05,FcnArgs{:});  % recompute the Jacobian
                twiceJip05 = 2*Jip05;
                % assembly
                dPHIdy(rows,cols) = -(In+hi/6*(Ji+twiceJip05*(In+hi/4*Ji)));
                cols = cols + n;
                dPHIdy(rows,cols) = In-hi/6*(Jip1+twiceJip05*(In-hi/4*Jip1));
                last_cols(rows,:) = -hi*dFdpar_ip05 + hi^2/12*Jip05* ...
                    (dFdpar_ip1-dFdpar_i);
                rows = rows+n;   % next equation
                
                Ji = Jip1;
                dFdpar_i = dFdpar_ip1;
            end
        end
        
        % Right BC
        dPHIdy(1:nBCs,cols) = dGdyb(:,(region-1)*n+(1:n));
        
        cols = cols + n;
    end
    
    dPHIdy(:,end-npar+1:end) = last_cols;  % accumulated
end

%---------------------------------------------------------------------------

function res = bcaux(Ya,Yb,n,bcfun,varargin)
ya = reshape(Ya,n,[]);
yb = reshape(Yb,n,[]);
res = bcfun(ya,yb,varargin{:});

%---------------------------------------------------------------------------

function [dBCdya,dBCdyb,nCalls,dBCdpar] = BCnumjac(bc,ya,yb,n,npar,dBCoptions,...
    nExtraArgs,ExtraArgs)
%BCNUMJAC  Numerically compute dBC/dya, dBC/dyb, and dBC/dpar, if needed.

% Do not pass info about singular BVPs in ExtraArgs to BC function.
bcArgs = {ya(:),yb(:),n,bc,ExtraArgs{1:nExtraArgs}};

bcVal  = bcaux(bcArgs{:});
nCalls = 1;

dBCoptions.fac = [];

dBCoptions.diffvar = 1;  % d(bc(ya,yb))/dya
[dBCdya,ignored,ignored1,nbc] = odenumjac(@bcaux,bcArgs,bcVal,dBCoptions);
nCalls = nCalls + nbc;

dBCoptions.diffvar = 2;
[dBCdyb,ignored,ignored1,nbc] = odenumjac(@bcaux,bcArgs,bcVal,dBCoptions);
nCalls = nCalls + nbc;

if npar > 0
    bcArgs = {ya,yb,ExtraArgs{1:nExtraArgs}};
    dPoptions.thresh = repmat(1e-6,npar,1);
    dPoptions.diffvar = 3;
    dPoptions.vectvars = [];
    dPoptions.fac = [];
    [dBCdpar,ignored,ignored1,nbc] = odenumjac(bc,bcArgs,bcVal,dPoptions);
    nCalls = nCalls + nbc;
end

%---------------------------------------------------------------------------

function [dFdy,dFdy_fac,dFdp,dFdp_fac,nFcalls] = Fnumjac(ode,odeArgs,odeVal,...
    Joptions,dPoptions)
%FNUMJAC  Numerically compute dF/dy and dF/dpar.

[dFdy,dFdy_fac,ignored,dFdy_nfcn] = odenumjac(ode,odeArgs,odeVal,Joptions);

[dFdp,dFdp_fac,ignored,dFdp_nfcn] = odenumjac(ode,odeArgs,odeVal,dPoptions);

nFcalls = dFdy_nfcn + dFdp_nfcn;

%---------------------------------------------------------------------------

function uintyp = uinttype(N)
%UINTTYPE Returns the approprate uint** type according to N
% junziyang 2009-05-30
if N<0
	error('N<0. Please use inttype instead.');
end
if N>intmax('uint32')
	uintyp = 'unit64';
elseif N>intmax('uint16')
	uintyp = 'unit32';
elseif N>intmax('uint8')
	uintyp = 'uint16';
else
	uintyp = 'uint8';
end

%---------------------------------------------------------------------------

Contact us at files@mathworks.com