function [ err_median_norms, err_median, g ] = ...
   polynomialGridTest(grid_size, which_polynomial, ...
                      stencil_size, stencil_shape, interpolate, show_plots)
% polynomialGridTest: Test curvature approximation on a polynomial function.  
%
%   [ err_median_norms, err_median, g ] = ...
%     polynomialGridTest(grid_size, which_polynomial, ...
%                        stencil_size, stencil_shape, interpolate, show_plots)
%
% Run either of the two 2D polynomial test cases from Table 1 of
%
%    Adam M. Oberman, "A Convergent Monotone Difference Scheme for Motion of
%    Level Sets by Mean Curvature," Numerische Mathematik, 99: 365-379
%    (2004), DOI: 10.1007/s00211-004-0566-1.
%
% This test samples the polynomials in question on an actual computational
% grid, and then uses oneLaplacian to approximate their curvature terms.
% This test is more representative of the accuracies that could be expected
% on a real grid than polynomialCircleTest.
%
% In addition to the output data, plots showing the actual curvature,
% the median approximation, and the standard centered difference
% approximation are generated.  Note that the output parameters only
% include information about the median approximation, not the standard
% centered difference approximation.
%
% Input Parameters:
%
%   grid_size: Positive integer scalar or two element column vector.  Number
%   of grid cells in each dimension.
%
%   which_polynomial: Positive Integer.  Which polynomial to test
%   against.  Current choices are 1 or 2.  See Oberman table 1 for the
%   specification of the polynomials.
%
%   stencil_size: Positive Integer.  Passed directly to oneLaplacian.m
%
%   stencil_shape: String.  Passed directly to oneLaplacian.m
%
%   interpolate: Boolean.  Passed directly to oneLaplacian.m
%
%   show_plots: Boolean.  Generate plots showing the curvature, its
%   approximations, and the errors?  Optional.  Default = 1.
%
% Output Parameters:
%
%   err_median_norms: Structure.  Members are .inf, .one, and .two.  Each
%   stores the appropriate error metric over the grid of the median
%   approximation.
%
%   err_median: Array.  Stores the error in the median approximation at each
%   node.
%
%   g: Grid structure on which the approximation is constructed.

% 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/18/07
% Modified parameters, Ian Mitchell, 6/13/07

  run('../../addPathToKernel');

  visualize_stencil = 0;
  
  if(nargin < 6)
    show_plots = 1;
  end
  
  %---------------------------------------------------------------------------
  % Create the grid.
  g.dim = 2;
  g.N = grid_size;
  g.min = -1;
  g.max = +1;
  g.bdry = @addGhostExtrapolate;
  g = processGrid(g);

  % How many nodes do you want to omit at the edges of the boundary
  % (since the BC are incorrect).
  bdry_width = ceil(stencil_size * 2 * max(g.dx) ./ g.dx);
  
  %---------------------------------------------------------------------------
  % These curvature solutions were computed using the symbolic math 
  % toolbox and polynomialSymbolic.m
  switch(which_polynomial)
   case 1
    polynomial = inline('6*x+5/4*y+9/4*x.^2+14/5*x.*y-13/5*y.^2', 'x', 'y');
    curvature = inline([ '-1/10*(888675+1499520*x+312400*y' ...
                         '+562320*x.^2+699776*x.*y-649792*y.^2)' ...
                         './(15025+24400*x+8240*y' ...
                         '+11236*x.^2-1568*x.*y+13952*y.^2)' ], 'x', 'y');
   case 2
    polynomial = inline('x-1/100*y+1/4*x.^2+31/10*x.*y-y.^2', 'x', 'y');
    curvature = inline([ '-1/2*(38759+424400*x-4244*y' ...
                         '+106100*x.^2+1315640*x.*y-424400*y.^2)' ...
                         './(10001+9380*x+62400*y' ...
                         '+98600*x.^2-93000*x.*y+136100*y.^2)' ], 'x', 'y');
    
   otherwise
    error('Unknown polynomial number: %s', which_polynomial);
  end
  
  %---------------------------------------------------------------------------
  % Analytic curvature and polynomial.
  poly_analytic = feval(polynomial, g.xs{1}, g.xs{2});
  curv_analytic = feval(curvature, g.xs{1}, g.xs{2});
  
  %---------------------------------------------------------------------------
  % Median based approximation of curvature on the entire grid.
  curv_approx_median = oneLaplacian(g, poly_analytic, ...
                                    stencil_size, stencil_shape, ...
                                    interpolate, visualize_stencil);
  
  %---------------------------------------------------------------------------
  % What does the error look like?
  err_median = abs(curv_approx_median - curv_analytic);

  % We know that the results near the boundary will be lousy.  Omit them.
  omit1 = bdry_width(1) : g.N(1) - bdry_width(1); 
  omit2 = bdry_width(2) : g.N(2) - bdry_width(2);
  err_median = err_median(omit1, omit2);
  
  err_median_norms.inf = max(err_median(:));
  err_median_norms.one = mean(err_median(:));
  err_median_norms.two = norm(err_median(:)) / sqrt(length(err_median(:)));

  %--------------------------------------------------------------------------- 
  if show_plots

    % Standard centered approximation of curvature on the entire grid,
    % for comparison
    [ kappa, gradMag ] = curvatureSecond(g, poly_analytic);
    curv_approx_centered = kappa .* gradMag;
    err_centered = abs(curv_approx_centered - curv_analytic);

    % Now generate some figures.
    figure;
    surf(g.xs{1}(omit1,omit2), g.xs{2}(omit1,omit2), err_median);
    xlabel('x');  ylabel('y');  zlabel('error');
    title({ [ 'Error in median curvature approx ' ...
              'for p' num2str(which_polynomial) ...
              ' on grid size ' num2str(grid_size') ...
              ' with ' stencil_shape ' stencil size ' num2str(stencil_size)]});

    figure;
    surf(g.xs{1}(omit1,omit2), g.xs{2}(omit1,omit2), ...
         err_centered(omit1,omit2));
    xlabel('x');  ylabel('y');  zlabel('error');
    title({ [ 'Error in centered curvature approx ' ...
              'for p' num2str(which_polynomial) ...
              ' on grid size ' num2str(grid_size') ] });
    figure;
    surf(g.xs{1}(omit1,omit2), g.xs{2}(omit1,omit2), ...
         poly_analytic(omit1,omit2));
    title({ [ 'Value of p' num2str(which_polynomial) ...
              ' on grid size ' num2str(grid_size') ] });
    figure
    surf(g.xs{1}(omit1,omit2), g.xs{2}(omit1,omit2), ...
         curv_analytic(omit1,omit2));
    title({ [ 'Analytic curvature for p' num2str(which_polynomial) ...
              ' on grid size ' num2str(grid_size') ] });
    figure
    surf(g.xs{1}(omit1,omit2), g.xs{2}(omit1,omit2), ...
         curv_approx_median(omit1,omit2));
    title({ [ 'Median curvature approx for p' num2str(which_polynomial) ...
              ' on grid size ' num2str(grid_size') ...
              ' with ' stencil_shape ' stencil size ' num2str(stencil_size)]});
    figure
    surf(g.xs{1}(omit1,omit2), g.xs{2}(omit1,omit2), ...
         curv_approx_centered(omit1,omit2));
    title({ [ 'Centered curvature approx for p' num2str(which_polynomial) ...
              ' on grid size ' num2str(grid_size') ] });
  end

  %keyboard;
