function [ t, y, schemeData ] = ...
          odeCFLsp(schemeFunc, tspan, y0, options, schemeData, integratorData)
% odeCFLsp: integrate a CFL constrained ODE (eg a PDE by method of lines).
%
% [ t, y, schemeData ] = ...
%         odeCFLsp(schemeFunc, tspan, y0, options, schemeData, integratorData)
%
% Integrates a system forward in time by CFL constrained timesteps using an
% s stage, order p scheme taken from the literature.  This routine does not
% integrate the system directly; instead, it contains alpha-beta parameter
% tables and calls odeCFLab to perform the timestepping.  For more
% details on the alpha-beta format, see odeCFLab.
%
% The supported schemes are:
%
%   s   p   CFL       source
%
%   1   1   1.0       shu_osher_88 (actually just Forward Euler)
%   2   2   1.0       shu_osher_88 (actually just modified Euler)
%   3   3   1.0       shu_osher_88
%
%   2   2   1.0       spiteri_ruuth_02 (same as shu_osher_88)
%   3   2   2.0       spiteri_ruuth_02
%   4   2   3.0       spiteri_ruuth_02
%   3   3   1.0       spiteri_ruuth_02 (same as shu_osher_88)
%   4   3   2.0       spiteri_ruuth_02
%   5   3   2.65062   spiteri_ruuth_02
%   5   4   1.50818   spiteri_ruuth_02
%
%   5   3   2.5(?)    spiteri_wang_07 (not SSP, should be stable with WENO5)
%
% We did not implement the spiteri_ruuth order 1 schemes, because they
% have not apparent speed benefit.
%
% The s, p, and source columns of the table are used to specify the scheme
% through the integratorData parameter (see below).  The CFL number given in
% the table is just the maximum specified in the literature (rounded down to
% the given precision).  It is up to the user to choose the CFL number for
% the integration via the options parameter and odeCFLset.  The papers given
% in the source column are:
%
%    C.-W. Shu & S. Osher, "Efficient Implementation of Essentially
%    Non-Oscillatory Shock-Capturing Schemes," J. Computational Physics,
%    v.77, pp. 439-471 (1988).
%
%    R. J. Spiteri & S. J. Ruuth, "A New Class of Optimal High-Order
%    Strong-Stability-Preserving Time Discretization Methods," SIAM
%    J. Numerical Analysis, v.40, n.2, pp. 469-491 (2002).
%
%    R. J. Spiteri & R. Wang, Personal communication.  Paper has been
%    submitted but is not yet publicly available.
%
% Input Parameters:
%
%   schemeFunc: Function handle to a CFL constrained ODE system (typically
%   an approximation to an HJ term, see below).
%
%   tspan: Range of time over which to integrate (see below).
%
%   y0: Initial condition vector (typically the data array in vector form).
%
%   options: An option structure generated by odeCFLset (use [] as a
%   placeholder if necessary).
%
%   schemeData: Structure passed through to schemeFunc.
%
%   integratorData: Structure of data used by this integration routine.
%
% Output Parameters:
%
%   t: Output time(s) (see below).
%
%   y: Output state (see below).
%
%   schemeData: Output version of schemeData (see below).
%
% integratorData is a structure containing data specific to this time
% integrator.  For this function it contains the field(s)
%
%   .source: A string taken from the table above.  Specifies which table of
%   alpha-beta parameters to use.
%
%   .s: Integer.  Number of steps in the scheme.  Taken from the table
%   above.  
%
%   .p: Integer.  Order of the scheme.  Taken from the table above.
%
% It may contain additional fields at the user's discretion.
%
%
% A CFL constrained ODE system is described by a function with prototype
%
%        [ ydot, stepBound ] = schemeFunc(t, y, schemeData)
%
% where t is the current time, y the current state vector and schemeData is
% passed directly through.  The output stepBound is the maximum allowed time
% step that will be taken by this function (typically the option parameter
% factorCFL will choose a smaller step size).
%
% The time interval tspan may be given as 
%   1) A two entry vector [ t0 tf ], in which case the output will 
%      be scalar t = tf and a row vector y = y(tf).
%
% Note that using this routine for integrating HJ PDEs will usually require
% that the data array be turned into a vector before the call and reshaped
% into an array after the call.  Option (2) for tspan should not be used in
% this case because of the excessive memory requirements for storing
% solutions at multiple timesteps.
%
% The output version of schemeData will normally be identical to the input
% version, and therefore can be ignored.  However, if a PostTimestep routine
% is used (see odeCFLset) then schemeData may be modified during
% integration, and the version of schemeData at tf is returned in this
% output argument.

% Copyright 2007 Ian M. Mitchell (mitchell@cs.ubc.ca).
% This software is used, copied and distributed under the licensing
% agreement contained in the file LICENSE in the top directory of the
% distribution.
%
% Ian Mitchell, 1/4/07.

  %----------------------------------------------------------------------
  % This routine does not work without source, s, and p parameters.
  % Check to make sure that they are well posed.
  if(nargin < 6)
    error('integratorData parameter is required');
  end

  checkStructureFields(integratorData, 'source', 's', 'p');

  %----------------------------------------------------------------------
  % The alpha-beta coefficient tables.  Indexing is (s,p).  Remember that
  % the alpha-beta arrays must be lower triangular

  % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  alpha.shu_osher_88 = cell(3,3);
  beta.shu_osher_88  = cell(3,3);

  alpha.shu_osher_88{1,1} = [ 1.0 ];
  beta.shu_osher_88{1,1}  = [ 1.0 ];

  alpha.shu_osher_88{2,2} = [ 1, 0; 1/2, 1/2 ];
  beta.shu_osher_88{2,2}  = [ 1, 0;   0,   1/2 ];
  
  alpha.shu_osher_88{3,3} = [ 1, 0,   0; 3/4, 1/4, 0; 1/3, 0,   2/3 ];
  beta.shu_osher_88{3,3}  = [ 1, 0,   0;   0, 1/4, 0;   0, 0,   2/3 ];

  % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  alpha.spiteri_ruuth_02 = cell(5,4);
  beta.spiteri_ruuth_02  = cell(5,4);

  alpha.spiteri_ruuth_02{2,2} = [ 1, 0; 1/2, 1/2 ];
  beta.spiteri_ruuth_02{2,2}  = [ 1, 0;   0, 1/2 ];

  alpha.spiteri_ruuth_02{3,2} = [   1,   0,   0;    0,   1, 0; 1/3,  0, 2/3 ];
  beta.spiteri_ruuth_02{3,2}  = [ 1/2,   0,   0;    0, 1/2, 0;   0,  0, 1/3 ];

  alpha.spiteri_ruuth_02{4,2} = [   1,   0,   0,   0;   0,   1,   0,   0; ...
                                    0,   0,   1,   0; 1/4,   0,   0, 3/4 ];
  beta.spiteri_ruuth_02{4,2}  = [ 1/3,   0,   0,   0;   0, 1/3,   0,   0; ...
                                    0,   0, 1/3,   0;   0,   0,   0, 1/4 ];

  alpha.spiteri_ruuth_02{3,3} = [   1,   0,   0; 3/4, 1/4, 0; 1/3,  0, 2/3 ];
  beta.spiteri_ruuth_02{3,3}  = [   1,   0,   0;   0, 1/4, 0;   0,  0, 2/3 ];

  alpha.spiteri_ruuth_02{4,3} = [   1,   0,   0,   0;   0,   1,   0,   0; ...
                                  2/3,   0, 1/3,   0;   0,   0,   0,   1 ];
  beta.spiteri_ruuth_02{4,3}  = [ 1/2,   0,   0,   0;   0, 1/2,   0,   0; ...
                                    0,   0, 1/6,   0;   0,   0,   0, 1/2 ];

  alpha.spiteri_ruuth_02{5,3} = ...
      [ 1.0, 0, 0, 0, 0; ...
        0, 1.0, 0, 0, 0; ...
        0.56656131914033, 0, 0.43343868085967, 0, 0; ... 
        0.09299483444413, 0.00002090369620, 0, 0.90698426185967, 0; ...
        0.00736132260920, 0.20127980325145, ...
        0.00182955389682, 0, 0.78952932024253 ];
  beta.spiteri_ruuth_02{5,3}  = ...
      [ 0.37726891511710, 0, 0, 0, 0; ...
        0, 0.37726891511710, 0, 0, 0; ...
        0, 0, 0.16352294089771, 0, 0; ...
        0.00071997378654, 0, 0, 0.34217696850008, 0; ...
        0.00277719819460, 0.00001567934613, 0, 0, 0.29786487010104 ];
                      
  alpha.spiteri_ruuth_02{5,4} = ...
      [ 1.0, 0, 0, 0, 0; ...
        0.44437049406734, 0.55562950593266, 0, 0, 0; ...
        0.62010185138540, 0, 0.37989814861460, 0, 0; ...
        0.17807995410773, 0, 0, 0.82192004589227, 0; ...
        0.00683325884039, 0, 0.51723167208978, ...
        0.12759831133288, 0.34833675773694 ];
  beta.spiteri_ruuth_02{5,4}  = ...
      [ 0.39175222700392, 0, 0, 0, 0; ...
        0, 0.36841059262959, 0, 0, 0; ...
        0, 0, 0.25189177424738, 0, 0; ...
        0, 0, 0, 0.54497475021237, 0; ...
        0, 0, 0, 0.08460416338212, 0.22600748319395 ];

  % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  alpha.spiteri_wang_07 = cell(5,3);
  beta.spiteri_wang_07  = cell(5,3);

  alpha.spiteri_wang_07{5,3} = ...
      [ 1, 0, 0, 0, 0; ...
        1, 0, 0, 0, 0; ...
        1, 0, 0, 0, 0; ...
        1, 0, 0, 0, 0; ...
        1, 0, 0, 0, 0 ];
  beta.spiteri_wang_07{5,3} = ...
      [ 1/7,    0,   0,   0,   0; ...
          0, 3/16,   0,   0,   0; ...
          0,    0, 1/3,   0,   0; ...
          0,    0,   0, 2/3,   0; ...
        1/4,    0,   0,   0, 3/4 ];
  
  %----------------------------------------------------------------------
  % Extract the relevant alpha-beta parameters.
  try
    alpha_table = alpha.(lower(integratorData.source));
    beta_table = beta.(lower(integratorData.source));
  catch
    error('Unrecognized source string: %s', integratorData.source);
  end

  try
    % If we can't index into the cell array at (s,p) then no scheme exists.
    abData.alpha = alpha_table{integratorData.s, integratorData.p};
    abData.beta = beta_table{integratorData.s, integratorData.p};
    % Force an error if alpha or beta are empty (also indicating that no scheme
    % exists for this combination of s & p).
    abData.alpha(1,1);
    abData.beta(1,1);
  catch
    error('No RK scheme for source = %s, s = %d, p = %d', ...
          integratorData.source, integratorData.s, integratorData.s);
  end
  
  
  %----------------------------------------------------------------------
  % Use odeCFLab to handle the actual integration.
  [ t, y, schemeData ] = ...
      odeCFLab(schemeFunc, tspan, y0, options, schemeData, abData);
