function a = phaseplot(odefun, xlimv, ylimv, xinit, T, varargin)
%PHASEPLOT   Phase plot for 2D dynamical systems
%
% PHASEPLOT('F', X1range, X2range) produces a quiver plot for the
% function 'F'.  X1range and X2range have the form [min, max, num]
% and specify the axis limits for the plot, along with the number
% of subdivisions in each axis, used to produce an quiver plot for
% the vector field.  
%
% The function 'F' should be the same for as used for ODE45.  Namely, it
% should be a function of the form dxdt = F(t,x) that accepts a state x of 
% dimension 2 and returns a derivative dxdt of dimension 2.
%
% PHASEPLOT('F', X1range, X2range, Xinit) produces a phase plot for
% the function 'F', consisting of the quiver plot plus stream lines.
% The streamlines start at the initial conditions listed in Xinit, 
% which should be a matrix whose rows give the desired inital
% conditions for x1 and x2.
%
% PHASEPLOT('F', X1range, X2range, boxgrid(X1range2, X2range2)) produces 
% a phase plot with stream lines generated at the edges of the rectangle
% defined by X1range2, X2range2.  These ranges are in the same form as
% X1range, X2range.
%
% PHASEPLOT('F', X1range, X2range, Xinit, T) produces a phase plot where
% the streamlines are simluted for time T (default = 50).
%
% PHASEPLOT('F', X1range, X2range, Xinit, T, P1, P2, ...) passes additional
% parameters to the function 'F', in the same way as ODE45.

% Written by Richard Murray, Fall 2002, based on a version by Kristi Morgansen
%
% 11 Oct 03, RMM: added parameters as additional arguments + dimen bug fix
%   * function now allows parameters in the same way as ODE45
%   * fixed bug with mesh dimensions caused by MATLAB length() behavior
%   * got completely frustrated with MATLAB as a psuedo-programming language

% Initialize the color grid
color = ['m', 'c', 'r', 'g', 'b', 'k', 'y'];

% Figure out the set of points for the quiver plot
[x1,x2] = meshgrid(xlimv(1):(xlimv(2)-xlimv(1))/xlimv(3):xlimv(2), ylimv(1):(ylimv(2)-ylimv(1))/ylimv(3):ylimv(2));

% Figure out if we have parameter arguments and create the required string
if (length(varargin) == 0)
  parms = '';
else
  parms = ', []';
  for (k = 1:length(varargin))
    parms = strcat(parms, sprintf(', %g', varargin{k}));
  end;
end;

% Now calculate the vector field at those points
[nr,nc] = size(x1);
for i = 1:nr
  for j = 1:nc
    eval(['dx(' num2str(i) ',' num2str(j) ',1:2) = ' ...
	odefun '(0, [' num2str(x1(i,j)) ' ' num2str(x2(i,j)) ']' parms ');']);
  end
end

% Plot the quiver plot
% clf; 
xy=quiver(x1,x2,dx(:,:,1),dx(:,:,2));
set(xy,'LineWidth',1);
a=gca; set(a,'DataAspectRatio',[1,1,1]);
set(a,'XLim',xlimv(1:2)); set(a,'YLim',ylimv(1:2));
xlabel('x_1'); ylabel('x_2','Rotation',0);

% See if we should also generate the streamlines
if (nargin < 4) return; end
  
% See if we were passed a simulation time
if (nargin < 5) T = 50; end

% Generate the streamlines for each initial condition
[nr, nc] = size(xinit);
for i = 1:nr
  [time, state] = ode45(odefun, [0 T], xinit(i,:), [], varargin{:});
  hold on;
  plot(state(:,1), state(:,2), color(mod(i-1, 7)+1));
end
set(a,'XLim',xlimv(1:2)); set(a,'YLim',ylimv(1:2));

